added support for BD game engine to Makefile for Android master-next-major-release 4.4.0.0-test-1
authorHolger Schemel <info@artsoft.org>
Wed, 8 May 2024 23:13:50 +0000 (01:13 +0200)
committerHolger Schemel <info@artsoft.org>
Wed, 8 May 2024 23:21:22 +0000 (01:21 +0200)
345 files changed:
.gitignore
CREDITS
Makefile
build-projects/android/SDL_VERSIONS
build-projects/android/app/build.gradle.tmpl
build-projects/android/app/src/main/AndroidManifest.xml.tmpl
build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/RocksNDiamonds.java [deleted file]
build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/rocksndiamonds.java [new file with mode: 0644]
build-projects/android/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
build-projects/android/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
build-projects/android/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
build-projects/android/app/src/main/java/org/libsdl/app/SDL.java
build-projects/android/app/src/main/java/org/libsdl/app/SDLActivity.java
build-projects/android/app/src/main/java/org/libsdl/app/SDLAudioManager.java
build-projects/android/app/src/main/java/org/libsdl/app/SDLControllerManager.java
build-projects/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
build-projects/android/app/src/main/res/mipmap-ldpi/ic_launcher.png
build-projects/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
build-projects/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
build-projects/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
build-projects/android/build.gradle
build-projects/android/gradle/wrapper/gradle-wrapper.properties
build-projects/emscripten/favicon-16x16.png [new file with mode: 0644]
build-projects/emscripten/favicon-32x32.png [new file with mode: 0644]
build-projects/emscripten/index.html
build-projects/emscripten/loading.svg [new file with mode: 0644]
build-projects/mac/Rocks'n'Diamonds.app/Contents/Frameworks/.gitkeep [new file with mode: 0644]
build-projects/mac/Rocks'n'Diamonds.app/Contents/Info.plist.template [new file with mode: 0644]
build-projects/mac/Rocks'n'Diamonds.app/Contents/MacOS/.gitkeep [new file with mode: 0644]
build-projects/mac/Rocks'n'Diamonds.app/Contents/PkgInfo [new file with mode: 0644]
build-projects/mac/Rocks'n'Diamonds.app/Contents/Resources/rocksndiamonds.icns [new file with mode: 0644]
build-projects/windows/icons/icon-128x128.png [new file with mode: 0644]
build-projects/windows/icons/icon-16x16.png [new file with mode: 0644]
build-projects/windows/icons/icon-32x32.png [new file with mode: 0644]
build-projects/windows/icons/icon-48x48.png [new file with mode: 0644]
build-projects/windows/rocksndiamonds.url [new file with mode: 0644]
build-projects/windows/template.iss [new file with mode: 0644]
build-scripts/create_element_defs.pl
docs/credits/credits_1.txt [new file with mode: 0644]
docs/credits/credits_10.txt [new file with mode: 0644]
docs/credits/credits_2.txt [new file with mode: 0644]
docs/credits/credits_3.txt [new file with mode: 0644]
docs/credits/credits_4.txt [new file with mode: 0644]
docs/credits/credits_5.txt [new file with mode: 0644]
docs/credits/credits_6.txt [new file with mode: 0644]
docs/credits/credits_7.txt [new file with mode: 0644]
docs/credits/credits_8.txt [new file with mode: 0644]
docs/credits/credits_9.txt [new file with mode: 0644]
docs/elements/bd_expandable_wall.txt [new file with mode: 0644]
docs/elements/bd_magic_wall.txt
docs/elements/bdx_acid.txt [new file with mode: 0644]
docs/elements/bdx_amoeba.txt [new file with mode: 0644]
docs/elements/bdx_amoeba_1.txt [new file with mode: 0644]
docs/elements/bdx_amoeba_2.txt [new file with mode: 0644]
docs/elements/bdx_biter.txt [new file with mode: 0644]
docs/elements/bdx_biter_switch.txt [new file with mode: 0644]
docs/elements/bdx_bladder.txt [new file with mode: 0644]
docs/elements/bdx_bladder_spender.txt [new file with mode: 0644]
docs/elements/bdx_bomb.txt [new file with mode: 0644]
docs/elements/bdx_box.txt [new file with mode: 0644]
docs/elements/bdx_butterfly.txt [new file with mode: 0644]
docs/elements/bdx_chasing_rock.txt [new file with mode: 0644]
docs/elements/bdx_clock.txt [new file with mode: 0644]
docs/elements/bdx_conveyor.txt [new file with mode: 0644]
docs/elements/bdx_conveyor_dir_switch.txt [new file with mode: 0644]
docs/elements/bdx_conveyor_switch.txt [new file with mode: 0644]
docs/elements/bdx_covered.txt [new file with mode: 0644]
docs/elements/bdx_cow.txt [new file with mode: 0644]
docs/elements/bdx_creature_switch.txt [new file with mode: 0644]
docs/elements/bdx_diamond.txt [new file with mode: 0644]
docs/elements/bdx_diamond_glued.txt [new file with mode: 0644]
docs/elements/bdx_diamond_key.txt [new file with mode: 0644]
docs/elements/bdx_dragonfly.txt [new file with mode: 0644]
docs/elements/bdx_exit.txt [new file with mode: 0644]
docs/elements/bdx_expandable_steelwall.txt [new file with mode: 0644]
docs/elements/bdx_expandable_wall.txt [new file with mode: 0644]
docs/elements/bdx_expandable_wall_switch.txt [new file with mode: 0644]
docs/elements/bdx_expanding_wall_switch.txt [new file with mode: 0644]
docs/elements/bdx_exploding.txt [new file with mode: 0644]
docs/elements/bdx_fake_bonus.txt [new file with mode: 0644]
docs/elements/bdx_falling_wall.txt [new file with mode: 0644]
docs/elements/bdx_firefly.txt [new file with mode: 0644]
docs/elements/bdx_flying_diamond.txt [new file with mode: 0644]
docs/elements/bdx_flying_rock.txt [new file with mode: 0644]
docs/elements/bdx_gate.txt [new file with mode: 0644]
docs/elements/bdx_ghost.txt [new file with mode: 0644]
docs/elements/bdx_gravestone.txt [new file with mode: 0644]
docs/elements/bdx_gravity_switch.txt [new file with mode: 0644]
docs/elements/bdx_inbox.txt [new file with mode: 0644]
docs/elements/bdx_invisible_exit.txt [new file with mode: 0644]
docs/elements/bdx_key.txt [new file with mode: 0644]
docs/elements/bdx_lava.txt [new file with mode: 0644]
docs/elements/bdx_magic_wall.txt [new file with mode: 0644]
docs/elements/bdx_mega_rock.txt [new file with mode: 0644]
docs/elements/bdx_nitro_pack.txt [new file with mode: 0644]
docs/elements/bdx_nut.txt [new file with mode: 0644]
docs/elements/bdx_player.txt [new file with mode: 0644]
docs/elements/bdx_pneumatic_hammer.txt [new file with mode: 0644]
docs/elements/bdx_pot.txt [new file with mode: 0644]
docs/elements/bdx_replicator.txt [new file with mode: 0644]
docs/elements/bdx_replicator_switch.txt [new file with mode: 0644]
docs/elements/bdx_rock.txt [new file with mode: 0644]
docs/elements/bdx_rock_glued.txt [new file with mode: 0644]
docs/elements/bdx_rocket.txt [new file with mode: 0644]
docs/elements/bdx_rocket_launcher.txt [new file with mode: 0644]
docs/elements/bdx_sand.txt [new file with mode: 0644]
docs/elements/bdx_sand_ball.txt [new file with mode: 0644]
docs/elements/bdx_sand_glued.txt [new file with mode: 0644]
docs/elements/bdx_sand_loose.txt [new file with mode: 0644]
docs/elements/bdx_sand_sloped.txt [new file with mode: 0644]
docs/elements/bdx_skeleton.txt [new file with mode: 0644]
docs/elements/bdx_slime.txt [new file with mode: 0644]
docs/elements/bdx_steelwall.txt [new file with mode: 0644]
docs/elements/bdx_steelwall_diggable.txt [new file with mode: 0644]
docs/elements/bdx_steelwall_explodable.txt [new file with mode: 0644]
docs/elements/bdx_steelwall_sloped.txt [new file with mode: 0644]
docs/elements/bdx_stonefly.txt [new file with mode: 0644]
docs/elements/bdx_sweet.txt [new file with mode: 0644]
docs/elements/bdx_teleporter.txt [new file with mode: 0644]
docs/elements/bdx_time_penalty.txt [new file with mode: 0644]
docs/elements/bdx_trapped_diamond.txt [new file with mode: 0644]
docs/elements/bdx_voodoo_doll.txt [new file with mode: 0644]
docs/elements/bdx_waiting_rock.txt [new file with mode: 0644]
docs/elements/bdx_wall.txt [new file with mode: 0644]
docs/elements/bdx_wall_diamond.txt [new file with mode: 0644]
docs/elements/bdx_wall_diggable.txt [new file with mode: 0644]
docs/elements/bdx_wall_key.txt [new file with mode: 0644]
docs/elements/bdx_wall_sloped.txt [new file with mode: 0644]
docs/elements/bdx_water.txt [new file with mode: 0644]
docs/elements/crystal.txt
docs/elements/dc_magic_wall.txt
docs/elements/df_mirror_fixed.txt [new file with mode: 0644]
docs/elements/df_slope.txt [new file with mode: 0644]
docs/elements/magic_wall.txt
docs/elements/mm_envelope.txt [new file with mode: 0644]
docs/elements/mm_exit.txt
docs/elements/mm_kettle.txt
docs/elements/mm_mcduffin.txt
docs/elements/mm_pacman.txt
docs/elements/sp_chip_bottom.txt
docs/elements/sp_chip_left.txt
docs/elements/sp_chip_right.txt
docs/elements/sp_chip_single.txt
docs/elements/sp_chip_top.txt
docs/elements/sp_hardware_base_1.txt
docs/elements/sp_hardware_base_2.txt
docs/elements/sp_hardware_base_3.txt
docs/elements/sp_hardware_base_4.txt
docs/elements/sp_hardware_base_5.txt
docs/elements/sp_hardware_base_6.txt
docs/elements/sp_hardware_blue.txt
docs/elements/sp_hardware_gray.txt
docs/elements/sp_hardware_green.txt
docs/elements/sp_hardware_red.txt
docs/elements/sp_hardware_yellow.txt
docs/elements/steelwall.txt
docs/program/program_1.txt [new file with mode: 0644]
graphics/gfx_classic/RocksBD.png [new file with mode: 0644]
graphics/gfx_classic/RocksBD2.png [new file with mode: 0644]
graphics/gfx_classic/RocksCE.png
graphics/gfx_classic/RocksCollect.png
graphics/gfx_classic/RocksDC.png
graphics/gfx_classic/RocksDC2.png
graphics/gfx_classic/RocksDF.png
graphics/gfx_classic/RocksDoor.png
graphics/gfx_classic/RocksDoor2.png
graphics/gfx_classic/RocksEMC.png
graphics/gfx_classic/RocksElements.png
graphics/gfx_classic/RocksIcon32x32.png [deleted file]
graphics/gfx_classic/RocksMM.png
graphics/gfx_classic/RocksSP.png
graphics/gfx_classic/RocksScreen.png
graphics/gfx_classic/RocksTouch.png
graphics/gfx_classic/icons/icon.png [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/000.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/001.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/002.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/003.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/004.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/005.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/006.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/007.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/README.txt [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchBars.png [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchPanel.png [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/graphics/graphicsinfo.conf [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/graphics/ncrtorial_title_screen.png [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/levelinfo.conf [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape.BROKEN [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/000_TAS.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/001.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/002.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/003.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/004.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/005.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/006.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/tapes/007.tape [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_ncrecc/unused.level [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_niko_boehm/README
levels/Tutorials/rnd_tutorial_niko_boehm/README.orig [new file with mode: 0644]
levels/Tutorials/rnd_tutorial_niko_boehm/README.txt [new file with mode: 0644]
music/mus_classic/rhythmloop.wav
sounds/snd_classic/autsch.wav
sounds/snd_classic/bong.wav
sounds/snd_classic/crash.wav [new file with mode: 0644]
sounds/snd_classic/fuel.wav
sounds/snd_classic/halloffame.wav
sounds/snd_classic/hammer.wav [new file with mode: 0644]
sounds/snd_classic/jingle.wav [new file with mode: 0644]
src/Android.mk
src/Makefile
src/anim.c
src/anim.h
src/api.c [new file with mode: 0644]
src/api.h [new file with mode: 0644]
src/conf_gfx.c
src/conf_mus.c
src/conf_snd.c
src/editor.c
src/editor.h
src/engines.h [deleted file]
src/events.c
src/events.h
src/files.c
src/files.h
src/game.c
src/game.h
src/game_bd/COPYING [new file with mode: 0644]
src/game_bd/Makefile [new file with mode: 0644]
src/game_bd/bd_bdcff.c [new file with mode: 0644]
src/game_bd/bd_bdcff.h [new file with mode: 0644]
src/game_bd/bd_c64import.c [new file with mode: 0644]
src/game_bd/bd_c64import.h [new file with mode: 0644]
src/game_bd/bd_cave.c [new file with mode: 0644]
src/game_bd/bd_cave.h [new file with mode: 0644]
src/game_bd/bd_cavedb.c [new file with mode: 0644]
src/game_bd/bd_cavedb.h [new file with mode: 0644]
src/game_bd/bd_caveengine.c [new file with mode: 0644]
src/game_bd/bd_caveengine.h [new file with mode: 0644]
src/game_bd/bd_caveobject.c [new file with mode: 0644]
src/game_bd/bd_caveobject.h [new file with mode: 0644]
src/game_bd/bd_caveset.c [new file with mode: 0644]
src/game_bd/bd_caveset.h [new file with mode: 0644]
src/game_bd/bd_colors.c [new file with mode: 0644]
src/game_bd/bd_colors.h [new file with mode: 0644]
src/game_bd/bd_elements.h [new file with mode: 0644]
src/game_bd/bd_gameplay.c [new file with mode: 0644]
src/game_bd/bd_gameplay.h [new file with mode: 0644]
src/game_bd/bd_graphics.c [new file with mode: 0644]
src/game_bd/bd_graphics.h [new file with mode: 0644]
src/game_bd/bd_random.c [new file with mode: 0644]
src/game_bd/bd_random.h [new file with mode: 0644]
src/game_bd/bd_sound.c [new file with mode: 0644]
src/game_bd/bd_sound.h [new file with mode: 0644]
src/game_bd/export_bd.h [new file with mode: 0644]
src/game_bd/game_bd.h [new file with mode: 0644]
src/game_bd/import_bd.h [new file with mode: 0644]
src/game_bd/main_bd.c [new file with mode: 0644]
src/game_bd/main_bd.h [new file with mode: 0644]
src/game_em/Makefile
src/game_em/cave.c
src/game_em/convert.c
src/game_em/export.h [deleted file]
src/game_em/export_em.h [new file with mode: 0644]
src/game_em/game.c
src/game_em/game_em.h
src/game_em/graphics.c
src/game_em/import_em.h [new file with mode: 0644]
src/game_em/logic.c
src/game_em/main_em.h
src/game_em/reademc.c
src/game_mm/Makefile
src/game_mm/export.h [deleted file]
src/game_mm/export_mm.h [new file with mode: 0644]
src/game_mm/game_mm.h
src/game_mm/import_mm.h [new file with mode: 0644]
src/game_mm/main_mm.h
src/game_mm/mm_files.c
src/game_mm/mm_game.c
src/game_mm/mm_game.h
src/game_mm/mm_init.c
src/game_mm/mm_main.c
src/game_mm/mm_main.h
src/game_mm/mm_tools.c
src/game_mm/mm_tools.h
src/game_sp/DDSpriteBuffer.c
src/game_sp/MainGameLoop.c
src/game_sp/MainGameLoop.h
src/game_sp/Makefile
src/game_sp/export.h [deleted file]
src/game_sp/export_sp.h [new file with mode: 0644]
src/game_sp/file.c
src/game_sp/game_sp.h
src/game_sp/import_sp.h [new file with mode: 0644]
src/game_sp/main.c
src/game_sp/main_sp.h
src/init.c
src/init.h
src/libgame/Makefile
src/libgame/base64.c
src/libgame/gadgets.c
src/libgame/gadgets.h
src/libgame/hash.c
src/libgame/hash.h
src/libgame/http.c
src/libgame/image.c
src/libgame/image.h
src/libgame/joystick.c
src/libgame/joystick.h
src/libgame/libgame.h
src/libgame/list.c [new file with mode: 0644]
src/libgame/list.h [new file with mode: 0644]
src/libgame/misc.c
src/libgame/misc.h
src/libgame/platform.h
src/libgame/random.c
src/libgame/random.h
src/libgame/sdl.c
src/libgame/sdl.h
src/libgame/setup.c
src/libgame/setup.h
src/libgame/sound.c
src/libgame/sound.h
src/libgame/system.c
src/libgame/system.h
src/libgame/text.c
src/libgame/text.h
src/libgame/types.h
src/libgame/zip/ioapi.c
src/libgame/zip/ioapi.h
src/libgame/zip/iowin32.c
src/libgame/zip/iowin32.h
src/libgame/zip/miniunz.c
src/libgame/zip/unzip.c
src/libgame/zip/unzip.h
src/main.c
src/main.h
src/netserv.h
src/screens.c
src/screens.h
src/tape.c
src/tape.h
src/tools.c
src/tools.h

index f0268317cbb5242ffe778155c9c3603f299f9569..2115c84b71949da28a5b6e365657b3a784228550 100644 (file)
@@ -15,6 +15,8 @@ src/conf_cus.c
 src/conf_cus.h
 src/conf_grp.c
 src/conf_grp.h
+src/conf_emp.c
+src/conf_emp.h
 src/conf_e2g.c
 src/conf_esg.c
 src/conf_e2s.c
diff --git a/CREDITS b/CREDITS
index 37026546731656a1cc8e41ceb53886396ec75ddf..2773d03a221cc93bfcfa7763d4f3795032be0711 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -7,14 +7,13 @@ somebody should be added to this list of credits, please let me know!
 
 Special thanks to Peter Liepa for creating "Boulder Dash" that started it all!
 
-Special thanks to Klaus Heinz and Volker Wertich for creating "Emerald Mine",
-which took this kind of game to a new level!
+Special thanks to Klaus Heinz and Volker Wertich for creating "Emerald Mine"!
 
 Special thanks to Michael Stopp and Philip Jespersen for creating "Supaplex"!
 
 Special thanks to Hiroyuki Imabayashi for creating "Sokoban"!
 
-Special thanks to Alan Bond and Jürgen Bonhagen for the continuous creation
+Special thanks to Alan Bond and Jürgen Bonhagen for the continuous creation
 of outstanding level sets!
 
 Thanks to Peter Elzner for ideas and inspiration by Diamond Caves.
@@ -23,18 +22,28 @@ Thanks to Steffest for ideas and inspiration by DX-Boulderdash.
 
 Thanks to Guido Schulz for the initial MS-DOS port of the game.
 
-The native Emerald mine engine was derived from Emerald Mine for X11
-which was developed by David Tritscher as a very compatible Emerald Mine clone.
-Thanks a lot for this contribution!
+The native Boulder Dash engine was derived from GDash, which was developed by
+Czirkos Zoltan as a highly compatible Boulder Dash clone. Thanks a lot for this
+contribution!
+
+The native Emerald mine engine was derived from Emerald Mine for X11, which was
+developed by David Tritscher as a very compatible Emerald Mine clone. Thanks a
+lot for this contribution!
 
 The native Supaplex engine is based on MegaPlex by Frank Schindler, which is
 based on the Supaplex Speed Fix by Herman Perk, which is based on the original
 Supaplex game by Michael Stopp and Philip Jespersen. Thanks a lot for this
 contribution!
 
-Thanks to Karl Hörnell for some additional toon graphics taken from "Iceblox":
+Thanks to Thomas Andrae for some additional toon graphics from Mirror Magic:
+The walking dwarf, the blue balloon jumper and the dwarf with five balloons.
+
+Thanks to Karl Hörnell for some additional toon graphics taken from "Iceblox":
 The penguin, the mole, the pig and the dragon.
 
+Thanks to Majid Katzer for some additional sounds and music from Mirror Magic:
+The hall of fame fanfare and the info screen rhythm loop.
+
 Thanks to the composers of the included music modules: "mod.apoplexy" by
 bee hunter/jazz, "mod.chiptune" by 4-mat/anarchy and "mod.cream_of_the_earth"
 by romeoknight.
@@ -47,7 +56,7 @@ The networking code was derived from xtris. Thanks!
 
 Thanks to Francesco Carta for the comprehensive Rocks'n'Diamonds manual.
 
-Thanks to Niko Böhm for the Rocks'n'Diamonds documentation wiki.
+Thanks to Niko Böhm for the Rocks'n'Diamonds documentation wiki.
 
 Thanks to Simon Forsberg for being the moderator of the R'n'D forum.
 
index 69fbf226a8305e0aae3ec98533917107999b05c5..e91a1bc75c6640a9beff4dad4e5da2d04d78e2f6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -116,6 +116,9 @@ tags:
 depend dep:
        $(MAKE_CMD) depend
 
+depend-clean dep-clean:
+       $(MAKE_CMD) depend-clean
+
 enginetest: all
        $(MAKE_ENGINETEST)
 
@@ -237,7 +240,7 @@ dist-upload-all:
 dist-deploy-all:
        $(MAKE) dist-deploy-emscripten
 
-dist-release-all: dist-package-all dist-copy-package-all dist-upload-all
+dist-release-all: dist-package-all dist-copy-package-all dist-upload-all dist-deploy-all
 
 package-all: dist-package-all
 
index b0613a715511441105eb103d73e35e5b8310344a..f4fd7015eda6ded271be0a98c245ff0809865a6b 100644 (file)
@@ -1,4 +1,4 @@
-SDL2-2.0.12
+SDL2-2.0.20
 SDL2_image-2.0.5
 SDL2_mixer-2.0.4
 SDL2_net-2.0.1
index 68c234b6726173c9a24bcebd915e848f0ab6c6dc..5eb4854dcd3892a6587643f47ee43b5f6abf9dc4 100644 (file)
@@ -8,7 +8,7 @@ else {
 }
 
 android {
-    compileSdkVersion 26
+    compileSdkVersion 31
 
     defaultConfig {
         if (buildAsApplication) {
@@ -16,7 +16,7 @@ android {
         }
 
         minSdkVersion 17
-        targetSdkVersion 26
+        targetSdkVersion 31
 
         versionCode  __VERSION_CODE__
         versionName "__VERSION_NAME__"
index 6e01acf90c11c0b77c25966c3daa413ca95cc392..8331804d0c5a7ddd0730fed9e61a7c2f44832cf4 100644 (file)
                  android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
                  android:hardwareAccelerated="true">
 
-        <activity android:name="RocksNDiamonds"
+        <activity android:name="rocksndiamonds"
                   android:label="@string/app_name"
                   android:alwaysRetainTaskState="true"
                   android:launchMode="singleInstance"
                  android:configChanges="keyboardHidden|orientation|screenSize"
+                 android:screenOrientation="fullUser"
+                 android:preferMinimalPostProcessing="true"
+                 android:exported="true"
                  >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/RocksNDiamonds.java b/build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/RocksNDiamonds.java
deleted file mode 100644 (file)
index 1415095..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-
-package org.artsoft.rocksndiamonds;
-
-import org.libsdl.app.SDLActivity;
-
-public class RocksNDiamonds extends SDLActivity { }
diff --git a/build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/rocksndiamonds.java b/build-projects/android/app/src/main/java/org/artsoft/rocksndiamonds/rocksndiamonds.java
new file mode 100644 (file)
index 0000000..eeec2ea
--- /dev/null
@@ -0,0 +1,6 @@
+
+package org.artsoft.rocksndiamonds;
+
+import org.libsdl.app.SDLActivity;
+
+public class rocksndiamonds extends SDLActivity { }
index 94a28189b8b476b957111d1ed265b96d4034105b..65c5a42370f28be3290ea3153f6261120ccfce7e 100644 (file)
@@ -564,10 +564,10 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         return "Steam Controller";
     }
 
-       @Override
+    @Override
     public UsbDevice getDevice() {
-               return null;
-       }
+        return null;
+    }
 
     @Override
     public boolean open() {
index 56f677e66017811570b286efdcba010272409efb..802c7254e68e85d528ed761bc9ea9156311eeb40 100644 (file)
@@ -7,6 +7,7 @@ import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothProfile;
+import android.os.Build;
 import android.util.Log;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -104,36 +105,6 @@ public class HIDDeviceManager {
     private HIDDeviceManager(final Context context) {
         mContext = context;
 
-        // Make sure we have the HIDAPI library loaded with the native functions
-        try {
-            SDL.loadLibrary("hidapi");
-        } catch (Throwable e) {
-            Log.w(TAG, "Couldn't load hidapi: " + e.toString());
-
-            AlertDialog.Builder builder = new AlertDialog.Builder(context);
-            builder.setCancelable(false);
-            builder.setTitle("SDL HIDAPI Error");
-            builder.setMessage("Please report the following error to the SDL maintainers: " + e.getMessage());
-            builder.setNegativeButton("Quit", new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialog, int which) {
-                    try {
-                        // If our context is an activity, exit rather than crashing when we can't
-                        // call our native functions.
-                        Activity activity = (Activity)context;
-        
-                        activity.finish();
-                    }
-                    catch (ClassCastException cce) {
-                        // Context wasn't an activity, there's nothing we can do.  Give up and return.
-                    }
-                }
-            });
-            builder.show();
-
-            return;
-        }
-        
         HIDDeviceRegisterCallback();
 
         mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
@@ -148,9 +119,6 @@ public class HIDDeviceManager {
         {
             mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
         }
-
-        initializeUSB();
-        initializeBluetooth();
     }
 
     public Context getContext() {
@@ -173,6 +141,9 @@ public class HIDDeviceManager {
 
     private void initializeUSB() {
         mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
+        if (mUsbManager == null) {
+            return;
+        }
 
         /*
         // Logging
@@ -275,6 +246,7 @@ public class HIDDeviceManager {
             0x15e4, // Numark
             0x162e, // Joytech
             0x1689, // Razer Onza
+            0x1949, // Lab126, Inc.
             0x1bad, // Harmonix
             0x24c6, // PowerA
         };
@@ -353,9 +325,18 @@ public class HIDDeviceManager {
 
     private void connectHIDDeviceUSB(UsbDevice usbDevice) {
         synchronized (this) {
+            int interface_mask = 0;
             for (int interface_index = 0; interface_index < usbDevice.getInterfaceCount(); interface_index++) {
                 UsbInterface usbInterface = usbDevice.getInterface(interface_index);
                 if (isHIDDeviceInterface(usbDevice, usbInterface)) {
+                    // Check to see if we've already added this interface
+                    // This happens with the Xbox Series X controller which has a duplicate interface 0, which is inactive
+                    int interface_id = usbInterface.getId();
+                    if ((interface_mask & (1 << interface_id)) != 0) {
+                        continue;
+                    }
+                    interface_mask |= (1 << interface_id);
+
                     HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
                     int id = device.getId();
                     mDevicesById.put(id, device);
@@ -368,11 +349,17 @@ public class HIDDeviceManager {
     private void initializeBluetooth() {
         Log.d(TAG, "Initializing Bluetooth");
 
-        if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+        if (Build.VERSION.SDK_INT <= 30 &&
+            mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
             Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
             return;
         }
 
+        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || (Build.VERSION.SDK_INT < 18)) {
+            Log.d(TAG, "Couldn't initialize Bluetooth, this version of Android does not support Bluetooth LE");
+            return;
+        }
+
         // Find bonded bluetooth controllers and create SteamControllers for them
         mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
         if (mBluetoothManager == null) {
@@ -555,6 +542,18 @@ public class HIDDeviceManager {
     ////////// JNI interface functions
     //////////////////////////////////////////////////////////////////////////////////////////////////////
 
+    public boolean initialize(boolean usb, boolean bluetooth) {
+        Log.v(TAG, "initialize(" + usb + ", " + bluetooth + ")");
+
+        if (usb) {
+            initializeUSB();
+        }
+        if (bluetooth) {
+            initializeBluetooth();
+        }
+        return true;
+    }
+
     public boolean openDevice(int deviceID) {
         Log.v(TAG, "openDevice deviceID=" + deviceID);
         HIDDevice device = getDevice(deviceID);
@@ -568,7 +567,14 @@ public class HIDDeviceManager {
         if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
             HIDDeviceOpenPending(deviceID);
             try {
-                mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
+                final int FLAG_MUTABLE = 0x02000000; // PendingIntent.FLAG_MUTABLE, but don't require SDK 31
+                int flags;
+                if (Build.VERSION.SDK_INT >= 31) {
+                    flags = FLAG_MUTABLE;
+                } else {
+                    flags = 0;
+                }
+                mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
             } catch (Exception e) {
                 Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
                 HIDDeviceOpenResult(deviceID, false);
index 33816e34484d4f7242ff5fbb1f28d56af13b0d93..d20fe80bc692b30590ecff4dd9153b1a1f788c32 100644 (file)
@@ -53,7 +53,12 @@ class HIDDeviceUSB implements HIDDevice {
     public String getSerialNumber() {
         String result = null;
         if (Build.VERSION.SDK_INT >= 21) {
-            result = mDevice.getSerialNumber();
+            try {
+                result = mDevice.getSerialNumber();
+            }
+            catch (SecurityException exception) {
+                //Log.w(TAG, "App permissions mean we cannot get serial number for device " + getDeviceName() + " message: " + exception.getMessage());
+            }
         }
         if (result == null) {
             result = "";
index fb7f7319a8979f6fae66be77cd14b94ce9fd01c1..dafc0cb87d58308faae8aa778d912e264d118978 100644 (file)
@@ -2,7 +2,8 @@ package org.libsdl.app;
 
 import android.content.Context;
 
-import java.lang.reflect.*;
+import java.lang.Class;
+import java.lang.reflect.Method;
 
 /**
     SDL library initialization
@@ -51,16 +52,16 @@ public class SDL {
             // To use ReLinker, just add it as a dependency.  For more information, see 
             // https://github.com/KeepSafe/ReLinker for ReLinker's repository.
             //
-            Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
-            Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
-            Class contextClass = mContext.getClassLoader().loadClass("android.content.Context");
-            Class stringClass = mContext.getClassLoader().loadClass("java.lang.String");
+            Class<?> relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
+            Class<?> relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
+            Class<?> contextClass = mContext.getClassLoader().loadClass("android.content.Context");
+            Class<?> stringClass = mContext.getClassLoader().loadClass("java.lang.String");
 
             // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if 
             // they've changed during updates.
             Method forceMethod = relinkClass.getDeclaredMethod("force");
             Object relinkInstance = forceMethod.invoke(null);
-            Class relinkInstanceClass = relinkInstance.getClass();
+            Class<?> relinkInstanceClass = relinkInstance.getClass();
 
             // Actually load the library!
             Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
@@ -77,7 +78,7 @@ public class SDL {
             catch (final SecurityException se) {
                 throw se;
             }
-        }        
+        }
     }
 
     protected static Context mContext;
index a61dd6db54dbd578f7a4304034cd9c12d8f4e774..da32aea2bdfbe452cba66b7f5e2aae73ebf6a447 100644 (file)
@@ -1,35 +1,62 @@
 package org.libsdl.app;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Hashtable;
-import java.lang.reflect.Method;
-import java.lang.Math;
-
-import android.app.*;
-import android.content.*;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.UiModeManager;
+import android.content.ClipboardManager;
+import android.content.ClipData;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.text.InputType;
-import android.view.*;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
-import android.widget.RelativeLayout;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
-import android.os.*;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.SparseArray;
-import android.graphics.*;
-import android.graphics.drawable.Drawable;
-import android.hardware.*;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ApplicationInfo;
+import android.widget.Toast;
+
+import java.util.Hashtable;
+import java.util.Locale;
+
 
 /**
     SDL Activity
@@ -41,7 +68,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     public static final boolean mHasMultiWindow = (Build.VERSION.SDK_INT >= 24);
 
     // Cursor types
-    private static final int SDL_SYSTEM_CURSOR_NONE = -1;
+    // private static final int SDL_SYSTEM_CURSOR_NONE = -1;
     private static final int SDL_SYSTEM_CURSOR_ARROW = 0;
     private static final int SDL_SYSTEM_CURSOR_IBEAM = 1;
     private static final int SDL_SYSTEM_CURSOR_WAIT = 2;
@@ -62,6 +89,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     protected static final int SDL_ORIENTATION_PORTRAIT_FLIPPED = 4;
 
     protected static int mCurrentOrientation;
+    protected static Locale mCurrentLocale;
 
     // Handle the state of the native layer
     public enum NativeState {
@@ -72,7 +100,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     public static NativeState mCurrentNativeState;
 
     /** If shared libraries (e.g. SDL or the native application) could not be loaded. */
-    public static boolean mBrokenLibraries;
+    public static boolean mBrokenLibraries = true;
 
     // Main components
     protected static SDLActivity mSingleton;
@@ -93,8 +121,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         if (mMotionListener == null) {
             if (Build.VERSION.SDK_INT >= 26) {
                 mMotionListener = new SDLGenericMotionListener_API26();
-            } else
-            if (Build.VERSION.SDK_INT >= 24) {
+            } else if (Build.VERSION.SDK_INT >= 24) {
                 mMotionListener = new SDLGenericMotionListener_API24();
             } else {
                 mMotionListener = new SDLGenericMotionListener_API12();
@@ -137,7 +164,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
      */
     protected String[] getLibraries() {
         return new String[] {
-            "hidapi",
             "SDL2",
             "SDL2_image",
             "SDL2_mixer",
@@ -175,7 +201,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         mCursors = new Hashtable<Integer, PointerIcon>();
         mLastCursorID = 0;
         mSDLThread = null;
-        mBrokenLibraries = false;
         mIsResumedCalled = false;
         mHasFocus = true;
         mNextNativeState = NativeState.INIT;
@@ -200,6 +225,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         String errorMsgBrokenLib = "";
         try {
             loadLibraries();
+            mBrokenLibraries = false; /* success */
         } catch(UnsatisfiedLinkError e) {
             System.err.println(e.getMessage());
             mBrokenLibraries = true;
@@ -243,7 +269,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         mSingleton = this;
         SDL.setContext(this);
 
-        mClipboardHandler = new SDLClipboardHandler_API11();
+        mClipboardHandler = new SDLClipboardHandler();
 
         mHIDDeviceManager = HIDDeviceManager.acquire(this);
 
@@ -258,6 +284,15 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         // Only record current orientation
         SDLActivity.onNativeOrientationChanged(mCurrentOrientation);
 
+        try {
+            if (Build.VERSION.SDK_INT < 24) {
+                mCurrentLocale = getContext().getResources().getConfiguration().locale;
+            } else {
+                mCurrentLocale = getContext().getResources().getConfiguration().getLocales().get(0);
+            }
+        } catch(Exception ignored) {
+        }
+
         setContentView(mLayout);
 
         setWindowStyle(false);
@@ -343,11 +378,14 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     }
 
     public static int getCurrentOrientation() {
-        final Context context = SDLActivity.getContext();
-        final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
-
         int result = SDL_ORIENTATION_UNKNOWN;
 
+        Activity activity = (Activity)getContext();
+        if (activity == null) {
+            return result;
+        }
+        Display display = activity.getWindowManager().getDefaultDisplay();
+
         switch (display.getRotation()) {
             case Surface.ROTATION_0:
                 result = SDL_ORIENTATION_PORTRAIT;
@@ -407,6 +445,21 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         SDLActivity.nativeLowMemory();
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        Log.v(TAG, "onConfigurationChanged()");
+        super.onConfigurationChanged(newConfig);
+
+        if (SDLActivity.mBrokenLibraries) {
+           return;
+        }
+
+        if (mCurrentLocale == null || !mCurrentLocale.equals(newConfig.locale)) {
+            mCurrentLocale = newConfig.locale;
+            SDLActivity.onNativeLocaleChanged();
+        }
+    }
+
     @Override
     protected void onDestroy() {
         Log.v(TAG, "onDestroy()");
@@ -446,8 +499,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         // If we do, the normal hardware back button will no longer work and people have to use home,
         // but the mouse right click will work.
         //
-        String trapBack = SDLActivity.nativeGetHint("SDL_ANDROID_TRAP_BACK_BUTTON");
-        if ((trapBack != null) && trapBack.equals("1")) {
+        boolean trapBack = SDLActivity.nativeGetHintBoolean("SDL_ANDROID_TRAP_BACK_BUTTON", false);
+        if (trapBack) {
             // Exit and let the mouse handler handle this button (if appropriate)
             return;
         }
@@ -540,11 +593,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                     mSDLThread.start();
 
                     // No nativeResume(), don't signal Android_ResumeSem
-                    mSurface.handleResume();
                 } else {
                     nativeResume();
-                    mSurface.handleResume();
                 }
+                mSurface.handleResume();
 
                 mCurrentNativeState = mNextNativeState;
             }
@@ -555,7 +607,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     static final int COMMAND_CHANGE_TITLE = 1;
     static final int COMMAND_CHANGE_WINDOW_STYLE = 2;
     static final int COMMAND_TEXTEDIT_HIDE = 3;
-    static final int COMMAND_CHANGE_SURFACEVIEW_FORMAT = 4;
     static final int COMMAND_SET_KEEP_SCREEN_ON = 5;
 
     protected static final int COMMAND_USER = 0x8000;
@@ -596,34 +647,32 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                 }
                 break;
             case COMMAND_CHANGE_WINDOW_STYLE:
-                if (Build.VERSION.SDK_INT < 19) {
-                    // This version of Android doesn't support the immersive fullscreen mode
-                    break;
-                }
-                if (context instanceof Activity) {
-                    Window window = ((Activity) context).getWindow();
-                    if (window != null) {
-                        if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
-                            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
+                if (Build.VERSION.SDK_INT >= 19) {
+                    if (context instanceof Activity) {
+                        Window window = ((Activity) context).getWindow();
+                        if (window != null) {
+                            if ((msg.obj instanceof Integer) && ((Integer) msg.obj != 0)) {
+                                int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
                                         View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                                         View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
                                         View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                                         View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                                         View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
-                            window.getDecorView().setSystemUiVisibility(flags);
-                            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
-                            window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
-                            SDLActivity.mFullscreenModeActive = true;
-                        } else {
-                            int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
-                            window.getDecorView().setSystemUiVisibility(flags);
-                            window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
-                            window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
-                            SDLActivity.mFullscreenModeActive = false;
+                                window.getDecorView().setSystemUiVisibility(flags);
+                                window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                                window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+                                SDLActivity.mFullscreenModeActive = true;
+                            } else {
+                                int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE;
+                                window.getDecorView().setSystemUiVisibility(flags);
+                                window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+                                window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+                                SDLActivity.mFullscreenModeActive = false;
+                            }
                         }
+                    } else {
+                        Log.e(TAG, "error handling message, getContext() returned no Activity");
                     }
-                } else {
-                    Log.e(TAG, "error handling message, getContext() returned no Activity");
                 }
                 break;
             case COMMAND_TEXTEDIT_HIDE:
@@ -646,7 +695,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                 if (context instanceof Activity) {
                     Window window = ((Activity) context).getWindow();
                     if (window != null) {
-                        if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) {
+                        if ((msg.obj instanceof Integer) && ((Integer) msg.obj != 0)) {
                             window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                         } else {
                             window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@@ -655,32 +704,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                 }
                 break;
             }
-            case COMMAND_CHANGE_SURFACEVIEW_FORMAT:
-            {
-                int format = (Integer) msg.obj;
-                int pf;
-
-                if (SDLActivity.mSurface == null) {
-                    return;
-                }
-
-                SurfaceHolder holder = SDLActivity.mSurface.getHolder();
-                if (holder == null) {
-                    return;
-                }
-
-                if (format == 1) {
-                    pf = PixelFormat.RGBA_8888;
-                } else if (format == 2) {
-                    pf = PixelFormat.RGBX_8888;
-                } else {
-                    pf = PixelFormat.RGB_565;
-                }
-
-                holder.setFormat(pf);
-
-                break;
-            }
             default:
                 if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
                     Log.e(TAG, "error handling message, command is " + msg.arg1);
@@ -699,53 +722,53 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         msg.obj = data;
         boolean result = commandHandler.sendMessage(msg);
 
-        if ((Build.VERSION.SDK_INT >= 19) && (command == COMMAND_CHANGE_WINDOW_STYLE)) {
-            // Ensure we don't return until the resize has actually happened,
-            // or 500ms have passed.
-
-            boolean bShouldWait = false;
-
-            if (data instanceof Integer) {
-                // Let's figure out if we're already laid out fullscreen or not.
-                Display display = ((WindowManager)getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
-                android.util.DisplayMetrics realMetrics = new android.util.DisplayMetrics();
-                display.getRealMetrics( realMetrics );
-
-                boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
-                                             (realMetrics.heightPixels == mSurface.getHeight()));
-
-                if (((Integer)data).intValue() == 1) {
-                    // If we aren't laid out fullscreen or actively in fullscreen mode already, we're going
-                    // to change size and should wait for surfaceChanged() before we return, so the size
-                    // is right back in native code.  If we're already laid out fullscreen, though, we're
-                    // not going to change size even if we change decor modes, so we shouldn't wait for
-                    // surfaceChanged() -- which may not even happen -- and should return immediately.
-                    bShouldWait = !bFullscreenLayout;
-                }
-                else {
-                    // If we're laid out fullscreen (even if the status bar and nav bar are present),
-                    // or are actively in fullscreen, we're going to change size and should wait for
-                    // surfaceChanged before we return, so the size is right back in native code.
-                    bShouldWait = bFullscreenLayout;
+        if (Build.VERSION.SDK_INT >= 19) {
+            if (command == COMMAND_CHANGE_WINDOW_STYLE) {
+                // Ensure we don't return until the resize has actually happened,
+                // or 500ms have passed.
+
+                boolean bShouldWait = false;
+
+                if (data instanceof Integer) {
+                    // Let's figure out if we're already laid out fullscreen or not.
+                    Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+                    DisplayMetrics realMetrics = new DisplayMetrics();
+                    display.getRealMetrics(realMetrics);
+
+                    boolean bFullscreenLayout = ((realMetrics.widthPixels == mSurface.getWidth()) &&
+                            (realMetrics.heightPixels == mSurface.getHeight()));
+
+                    if ((Integer) data == 1) {
+                        // If we aren't laid out fullscreen or actively in fullscreen mode already, we're going
+                        // to change size and should wait for surfaceChanged() before we return, so the size
+                        // is right back in native code.  If we're already laid out fullscreen, though, we're
+                        // not going to change size even if we change decor modes, so we shouldn't wait for
+                        // surfaceChanged() -- which may not even happen -- and should return immediately.
+                        bShouldWait = !bFullscreenLayout;
+                    } else {
+                        // If we're laid out fullscreen (even if the status bar and nav bar are present),
+                        // or are actively in fullscreen, we're going to change size and should wait for
+                        // surfaceChanged before we return, so the size is right back in native code.
+                        bShouldWait = bFullscreenLayout;
+                    }
                 }
-            }
 
-            if (bShouldWait && (SDLActivity.getContext() != null)) {
-                // We'll wait for the surfaceChanged() method, which will notify us
-                // when called.  That way, we know our current size is really the
-                // size we need, instead of grabbing a size that's still got
-                // the navigation and/or status bars before they're hidden.
-                //
-                // We'll wait for up to half a second, because some devices
-                // take a surprisingly long time for the surface resize, but
-                // then we'll just give up and return.
-                //
-                synchronized(SDLActivity.getContext()) {
-                    try {
-                        SDLActivity.getContext().wait(500);
-                    }
-                    catch (InterruptedException ie) {
-                        ie.printStackTrace();
+                if (bShouldWait && (SDLActivity.getContext() != null)) {
+                    // We'll wait for the surfaceChanged() method, which will notify us
+                    // when called.  That way, we know our current size is really the
+                    // size we need, instead of grabbing a size that's still got
+                    // the navigation and/or status bars before they're hidden.
+                    //
+                    // We'll wait for up to half a second, because some devices
+                    // take a surprisingly long time for the surface resize, but
+                    // then we'll just give up and return.
+                    //
+                    synchronized (SDLActivity.getContext()) {
+                        try {
+                            SDLActivity.getContext().wait(500);
+                        } catch (InterruptedException ie) {
+                            ie.printStackTrace();
+                        }
                     }
                 }
             }
@@ -764,7 +787,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     public static native void nativeResume();
     public static native void nativeFocusChanged(boolean hasFocus);
     public static native void onNativeDropFile(String filename);
-    public static native void nativeSetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, int format, float rate);
+    public static native void nativeSetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float rate);
     public static native void onNativeResize();
     public static native void onNativeKeyDown(int keycode);
     public static native void onNativeKeyUp(int keycode);
@@ -780,10 +803,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     public static native void onNativeSurfaceChanged();
     public static native void onNativeSurfaceDestroyed();
     public static native String nativeGetHint(String name);
+    public static native boolean nativeGetHintBoolean(String name, boolean default_value);
     public static native void nativeSetenv(String name, String value);
     public static native void onNativeOrientationChanged(int orientation);
     public static native void nativeAddTouch(int touchId, String name);
     public static native void nativePermissionResult(int requestCode, boolean result);
+    public static native void onNativeLocaleChanged();
 
     /**
      * This method is called by SDL using JNI.
@@ -838,15 +863,15 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             orientation_portrait = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
         }
 
-        boolean is_landscape_allowed = (orientation_landscape == -1 ? false : true);
-        boolean is_portrait_allowed = (orientation_portrait == -1 ? false : true);
-        int req = -1; /* Requested orientation */
+        boolean is_landscape_allowed = (orientation_landscape != -1);
+        boolean is_portrait_allowed = (orientation_portrait != -1);
+        int req; /* Requested orientation */
 
         /* No valid hint, nothing is explicitly allowed */
         if (!is_portrait_allowed && !is_landscape_allowed) {
             if (resizable) {
                 /* All orientations are allowed */
-                req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+                req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
             } else {
                 /* Fixed window and nothing specified. Get orientation from w/h of created window */
                 req = (w > h ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
@@ -856,7 +881,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             if (resizable) {
                 if (is_portrait_allowed && is_landscape_allowed) {
                     /* hint allows both landscape and portrait, promote to full sensor */
-                    req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+                    req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
                 } else {
                     /* Use the only one allowed "orientation" */
                     req = (is_landscape_allowed ? orientation_landscape : orientation_portrait);
@@ -872,7 +897,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             }
         }
 
-        Log.v("SDL", "setOrientation() requestedOrientation=" + req + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
+        Log.v(TAG, "setOrientation() requestedOrientation=" + req + " width=" + w +" height="+ h +" resizable=" + resizable + " hint=" + hint);
         mSingleton.setRequestedOrientation(req);
     }
 
@@ -938,11 +963,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
      */
     public static boolean supportsRelativeMouse()
     {
-        // ChromeOS doesn't provide relative mouse motion via the Android 7 APIs
-        if (isChromebook()) {
-            return false;
-        }
-
         // DeX mode in Samsung Experience 9.0 and earlier doesn't support relative mice properly under
         // Android 7 APIs, and simply returns no data under Android 8 APIs.
         //
@@ -976,7 +996,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         if (mSingleton == null) {
             return false;
         }
-        return mSingleton.sendCommand(command, Integer.valueOf(param));
+        return mSingleton.sendCommand(command, param);
     }
 
     /**
@@ -1000,30 +1020,30 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         if (Build.MANUFACTURER.equals("Amlogic") && Build.MODEL.equals("X96-W")) {
             return true;
         }
-        if (Build.MANUFACTURER.equals("Amlogic") && Build.MODEL.startsWith("TV")) {
-            return true;
-        }
-        return false;
+        return Build.MANUFACTURER.equals("Amlogic") && Build.MODEL.startsWith("TV");
     }
 
-    /**
-     * This method is called by SDL using JNI.
-     */
-    public static boolean isTablet() {
+    public static double getDiagonal()
+    {
         DisplayMetrics metrics = new DisplayMetrics();
         Activity activity = (Activity)getContext();
         if (activity == null) {
-            return false;
+            return 0.0;
         }
         activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
 
         double dWidthInches = metrics.widthPixels / (double)metrics.xdpi;
         double dHeightInches = metrics.heightPixels / (double)metrics.ydpi;
 
-        double dDiagonal = Math.sqrt((dWidthInches * dWidthInches) + (dHeightInches * dHeightInches));
+        return Math.sqrt((dWidthInches * dWidthInches) + (dHeightInches * dHeightInches));
+    }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static boolean isTablet() {
         // If our diagonal size is seven inches or greater, we consider ourselves a tablet.
-        return (dDiagonal >= 7.0);
+        return (getDiagonal() >= 7.0);
     }
 
     /**
@@ -1045,7 +1065,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         }
         try {
             final Configuration config = getContext().getResources().getConfiguration();
-            final Class configClass = config.getClass();
+            final Class<?> configClass = config.getClass();
             return configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass)
                     == configClass.getField("semDesktopModeEnabled").getInt(config);
         } catch(Exception ignored) {
@@ -1065,6 +1085,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
      */
     public static boolean getManifestEnvironmentVariables() {
         try {
+            if (getContext() == null) {
+                return false;
+            }
+
             ApplicationInfo applicationInfo = getContext().getPackageManager().getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
             Bundle bundle = applicationInfo.metaData;
             if (bundle == null) {
@@ -1082,7 +1106,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             /* environment variables set! */
             return true;
         } catch (Exception e) {
-           Log.v("SDL", "exception " + e.toString());
+           Log.v(TAG, "exception " + e.toString());
         }
         return false;
     }
@@ -1090,7 +1114,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     // This method is called by SDLControllerManager's API 26 Generic Motion Handler.
     public static View getContentView()
     {
-        return mSingleton.mLayout;
+        return mLayout;
     }
 
     static class ShowTextInputTask implements Runnable {
@@ -1170,14 +1194,6 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         return SDLActivity.mSurface.getNativeSurface();
     }
 
-    /**
-     * This method is called by SDL using JNI.
-     */
-    public static void setSurfaceViewFormat(int format) {
-        mSingleton.sendCommand(COMMAND_CHANGE_SURFACEVIEW_FORMAT, format);
-        return;
-    }
-
     // Input
 
     /**
@@ -1186,92 +1202,19 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     public static void initTouch() {
         int[] ids = InputDevice.getDeviceIds();
 
-        for (int i = 0; i < ids.length; ++i) {
-            InputDevice device = InputDevice.getDevice(ids[i]);
+        for (int id : ids) {
+            InputDevice device = InputDevice.getDevice(id);
             if (device != null && (device.getSources() & InputDevice.SOURCE_TOUCHSCREEN) != 0) {
                 nativeAddTouch(device.getId(), device.getName());
             }
         }
     }
 
-    // APK expansion files support
-
-    /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
-    private static Object expansionFile;
-
-    /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
-    private static Method expansionFileMethod;
-
-    /**
-     * This method is called by SDL using JNI.
-     * @return an InputStream on success or null if no expansion file was used.
-     * @throws IOException on errors. Message is set for the SDL error message.
-     */
-    public static InputStream openAPKExpansionInputStream(String fileName) throws IOException {
-        // Get a ZipResourceFile representing a merger of both the main and patch files
-        if (expansionFile == null) {
-            String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
-            if (mainHint == null) {
-                return null; // no expansion use if no main version was set
-            }
-            String patchHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION");
-            if (patchHint == null) {
-                return null; // no expansion use if no patch version was set
-            }
-
-            Integer mainVersion;
-            Integer patchVersion;
-            try {
-                mainVersion = Integer.valueOf(mainHint);
-                patchVersion = Integer.valueOf(patchHint);
-            } catch (NumberFormatException ex) {
-                ex.printStackTrace();
-                throw new IOException("No valid file versions set for APK expansion files", ex);
-            }
-
-            try {
-                // To avoid direct dependency on Google APK expansion library that is
-                // not a part of Android SDK we access it using reflection
-                expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
-                    .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
-                    .invoke(null, SDL.getContext(), mainVersion, patchVersion);
-
-                expansionFileMethod = expansionFile.getClass()
-                    .getMethod("getInputStream", String.class);
-            } catch (Exception ex) {
-                ex.printStackTrace();
-                expansionFile = null;
-                expansionFileMethod = null;
-                throw new IOException("Could not access APK expansion support library", ex);
-            }
-        }
-
-        // Get an input stream for a known file inside the expansion file ZIPs
-        InputStream fileStream;
-        try {
-            fileStream = (InputStream)expansionFileMethod.invoke(expansionFile, fileName);
-        } catch (Exception ex) {
-            // calling "getInputStream" failed
-            ex.printStackTrace();
-            throw new IOException("Could not open stream from APK expansion file", ex);
-        }
-
-        if (fileStream == null) {
-            // calling "getInputStream" was successful but null was returned
-            throw new IOException("Could not find path in APK expansion file");
-        }
-
-        return fileStream;
-    }
-
     // Messagebox
 
     /** Result of current messagebox. Also used for blocking the calling thread. */
     protected final int[] messageboxSelection = new int[1];
 
-    /** Id of current dialog. */
-    protected int dialogs = 0;
-
     /**
      * This method is called by SDL using JNI.
      * Shows the messagebox from UI thread and block calling thread.
@@ -1315,7 +1258,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         runOnUiThread(new Runnable() {
             @Override
             public void run() {
-                showDialog(dialogs++, args);
+                messageboxCreateAndShow(args);
             }
         });
 
@@ -1335,8 +1278,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         return messageboxSelection[0];
     }
 
-    @Override
-    protected Dialog onCreateDialog(int ignore, Bundle args) {
+    protected void messageboxCreateAndShow(Bundle args) {
 
         // TODO set values from "flags" to messagebox dialog
 
@@ -1365,7 +1307,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
 
         // create dialog with title and a listener to wake up calling thread
 
-        final Dialog dialog = new Dialog(this);
+        final AlertDialog dialog = new AlertDialog.Builder(this).create();
         dialog.setTitle(args.getString("title"));
         dialog.setCancelable(false);
         dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@@ -1451,7 +1393,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
 
         // add content to dialog and return
 
-        dialog.setContentView(content);
+        dialog.setView(content);
         dialog.setOnKeyListener(new Dialog.OnKeyListener() {
             @Override
             public boolean onKey(DialogInterface d, int keyCode, KeyEvent event) {
@@ -1466,20 +1408,22 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             }
         });
 
-        return dialog;
+        dialog.show();
     }
 
     private final Runnable rehideSystemUi = new Runnable() {
         @Override
         public void run() {
-            int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
+            if (Build.VERSION.SDK_INT >= 19) {
+                int flags = View.SYSTEM_UI_FLAG_FULLSCREEN |
                         View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
                         View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
                         View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                         View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
                         View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.INVISIBLE;
 
-            SDLActivity.this.getWindow().getDecorView().setSystemUiVisibility(flags);
+                SDLActivity.this.getWindow().getDecorView().setSystemUiVisibility(flags);
+            }
         }
     };
 
@@ -1535,6 +1479,19 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         return mLastCursorID;
     }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static void destroyCustomCursor(int cursorID) {
+        if (Build.VERSION.SDK_INT >= 24) {
+            try {
+                mCursors.remove(cursorID);
+            } catch (Exception e) {
+            }
+        }
+        return;
+    }
+
     /**
      * This method is called by SDL using JNI.
      */
@@ -1624,11 +1581,78 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
 
     @Override
     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
-        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
-            nativePermissionResult(requestCode, true);
-        } else {
-            nativePermissionResult(requestCode, false);
+        boolean result = (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED);
+        nativePermissionResult(requestCode, result);
+    }
+
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static int openURL(String url)
+    {
+        try {
+            Intent i = new Intent(Intent.ACTION_VIEW);
+            i.setData(Uri.parse(url));
+
+            int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+            if (Build.VERSION.SDK_INT >= 21) {
+                flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+            } else {
+                flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
+            }
+            i.addFlags(flags);
+
+            mSingleton.startActivity(i);
+        } catch (Exception ex) {
+            return -1;
+        }
+        return 0;
+    }
+
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static int showToast(String message, int duration, int gravity, int xOffset, int yOffset)
+    {
+        if(null == mSingleton) {
+            return - 1;
+        }
+
+        try
+        {
+            class OneShotTask implements Runnable {
+                String mMessage;
+                int mDuration;
+                int mGravity;
+                int mXOffset;
+                int mYOffset;
+
+                OneShotTask(String message, int duration, int gravity, int xOffset, int yOffset) {
+                    mMessage  = message;
+                    mDuration = duration;
+                    mGravity  = gravity;
+                    mXOffset  = xOffset;
+                    mYOffset  = yOffset;
+                }
+
+                public void run() {
+                    try
+                    {
+                        Toast toast = Toast.makeText(mSingleton, mMessage, mDuration);
+                        if (mGravity >= 0) {
+                            toast.setGravity(mGravity, mXOffset, mYOffset);
+                        }
+                        toast.show();
+                    } catch(Exception ex) {
+                        Log.e(TAG, ex.getMessage());
+                    }
+                }
+            }
+            mSingleton.runOnUiThread(new OneShotTask(message, duration, gravity, xOffset, yOffset));
+        } catch(Exception ex) {
+            return -1;
         }
+        return 0;
     }
 }
 
@@ -1655,13 +1679,12 @@ class SDLMain implements Runnable {
 
         Log.v("SDL", "Finished main function");
 
-        if (SDLActivity.mSingleton == null || SDLActivity.mSingleton.isFinishing()) {
-            // Activity is already being destroyed
-        } else {
+        if (SDLActivity.mSingleton != null && !SDLActivity.mSingleton.isFinishing()) {
             // Let's finish the Activity
             SDLActivity.mSDLThread = null;
             SDLActivity.mSingleton.finish();
-        }
+        }  // else: Activity is already being destroyed
+
     }
 }
 
@@ -1755,30 +1778,6 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             return;
         }
 
-        int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
-        switch (format) {
-        case PixelFormat.RGBA_8888:
-            Log.v("SDL", "pixel format RGBA_8888");
-            sdlFormat = 0x16462004; // SDL_PIXELFORMAT_RGBA8888
-            break;
-        case PixelFormat.RGBX_8888:
-            Log.v("SDL", "pixel format RGBX_8888");
-            sdlFormat = 0x16261804; // SDL_PIXELFORMAT_RGBX8888
-            break;
-        case PixelFormat.RGB_565:
-            Log.v("SDL", "pixel format RGB_565");
-            sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565
-            break;
-        case PixelFormat.RGB_888:
-            Log.v("SDL", "pixel format RGB_888");
-            // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
-            sdlFormat = 0x16161804; // SDL_PIXELFORMAT_RGB888
-            break;
-        default:
-            Log.v("SDL", "pixel format unknown " + format);
-            break;
-        }
-
         mWidth = width;
         mHeight = height;
         int nDeviceWidth = width;
@@ -1786,13 +1785,13 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         try
         {
             if (Build.VERSION.SDK_INT >= 17) {
-                android.util.DisplayMetrics realMetrics = new android.util.DisplayMetrics();
+                DisplayMetrics realMetrics = new DisplayMetrics();
                 mDisplay.getRealMetrics( realMetrics );
                 nDeviceWidth = realMetrics.widthPixels;
                 nDeviceHeight = realMetrics.heightPixels;
             }
+        } catch(Exception ignored) {
         }
-        catch ( java.lang.Throwable throwable ) {}
 
         synchronized(SDLActivity.getContext()) {
             // In case we're waiting on a size change after going fullscreen, send a notification.
@@ -1801,7 +1800,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
 
         Log.v("SDL", "Window size: " + width + "x" + height);
         Log.v("SDL", "Device size: " + nDeviceWidth + "x" + nDeviceHeight);
-        SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, sdlFormat, mDisplay.getRefreshRate());
+        SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, mDisplay.getRefreshRate());
         SDLActivity.onNativeResize();
 
         // Prevent a screen distortion glitch,
@@ -1809,12 +1808,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         boolean skip = false;
         int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation();
 
-        if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
-        {
-            // Accept any
-        }
-        else if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT)
-        {
+        if (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
             if (mWidth > mHeight) {
                skip = true;
             }
@@ -1868,6 +1862,19 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         int deviceId = event.getDeviceId();
         int source = event.getSource();
 
+        if (source == InputDevice.SOURCE_UNKNOWN) {
+            InputDevice device = InputDevice.getDevice(deviceId);
+            if (device != null) {
+                source = device.getSources();
+            }
+        }
+
+//        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+//            Log.v("SDL", "key down: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
+//        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+//            Log.v("SDL", "key up: " + keyCode + ", deviceId = " + deviceId + ", source = " + source);
+//        }
+
         // Dispatch the different events depending on where they come from
         // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
         // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
@@ -1888,24 +1895,14 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
         }
 
-        if (source == InputDevice.SOURCE_UNKNOWN) {
-            InputDevice device = InputDevice.getDevice(deviceId);
-            if (device != null) {
-                source = device.getSources();
-            }
-        }
-
         if ((source & InputDevice.SOURCE_KEYBOARD) != 0) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                //Log.v("SDL", "key down: " + keyCode);
                 if (SDLActivity.isTextInputEvent(event)) {
                     SDLInputConnection.nativeCommitText(String.valueOf((char) event.getUnicodeChar()), 1);
                 }
                 SDLActivity.onNativeKeyDown(keyCode);
                 return true;
-            }
-            else if (event.getAction() == KeyEvent.ACTION_UP) {
-                //Log.v("SDL", "key up: " + keyCode);
+            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                 SDLActivity.onNativeKeyUp(keyCode);
                 return true;
             }
@@ -1932,22 +1929,34 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         /* Ref: http://developer.android.com/training/gestures/multi.html */
-        final int touchDevId = event.getDeviceId();
+        int touchDevId = event.getDeviceId();
         final int pointerCount = event.getPointerCount();
         int action = event.getActionMasked();
         int pointerFingerId;
-        int mouseButton;
         int i = -1;
         float x,y,p;
 
+        /*
+         * Prevent id to be -1, since it's used in SDL internal for synthetic events
+         * Appears when using Android emulator, eg:
+         *  adb shell input mouse tap 100 100
+         *  adb shell input touchscreen tap 100 100
+         */
+        if (touchDevId < 0) {
+            touchDevId -= 1;
+        }
+
         // 12290 = Samsung DeX mode desktop mouse
         // 12290 = 0x3002 = 0x2002 | 0x1002 = SOURCE_MOUSE | SOURCE_TOUCHSCREEN
         // 0x2   = SOURCE_CLASS_POINTER
         if (event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == (InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN)) {
+            int mouseButton = 1;
             try {
-                mouseButton = (Integer) event.getClass().getMethod("getButtonState").invoke(event);
-            } catch(Exception e) {
-                mouseButton = 1;    // oh well.
+                Object object = event.getClass().getMethod("getButtonState").invoke(event);
+                if (object != null) {
+                    mouseButton = (Integer) object;
+                }
+            } catch(Exception ignored) {
             }
 
             // We need to check if we're in relative mouse mode and get the axis offset rather than the x/y values
@@ -1978,6 +1987,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                 case MotionEvent.ACTION_DOWN:
                     // Primary pointer up/down, the index is always zero
                     i = 0;
+                    /* fallthrough */
                 case MotionEvent.ACTION_POINTER_UP:
                 case MotionEvent.ACTION_POINTER_DOWN:
                     // Non primary pointer up/down
@@ -2044,7 +2054,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
 
             // Since we may have an orientation set, we won't receive onConfigurationChanged events.
             // We thus should check here.
-            int newOrientation = SDLActivity.SDL_ORIENTATION_UNKNOWN;
+            int newOrientation;
 
             float x, y;
             switch (mDisplay.getRotation()) {
@@ -2063,6 +2073,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                     y = -event.values[1];
                     newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT_FLIPPED;
                     break;
+                case Surface.ROTATION_0:
                 default:
                     x = event.values[0];
                     y = event.values[1];
@@ -2109,8 +2120,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                 // Change our action value to what SDL's code expects.
                 if (action == MotionEvent.ACTION_BUTTON_PRESS) {
                     action = MotionEvent.ACTION_DOWN;
-                }
-                else if (action == MotionEvent.ACTION_BUTTON_RELEASE) {
+                } else { /* MotionEvent.ACTION_BUTTON_RELEASE */
                     action = MotionEvent.ACTION_UP;
                 }
 
@@ -2173,7 +2183,7 @@ class DummyEdit extends View implements View.OnKeyListener {
         // FIXME: A more effective solution would be to assume our Layout to be RelativeLayout or LinearLayout
         // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
         // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
-        if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
+        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
             if (SDLActivity.mTextEdit != null && SDLActivity.mTextEdit.getVisibility() == View.VISIBLE) {
                 SDLActivity.onNativeKeyboardFocusLost();
             }
@@ -2275,45 +2285,38 @@ class SDLInputConnection extends BaseInputConnection {
     }
 }
 
-interface SDLClipboardHandler {
-
-    public boolean clipboardHasText();
-    public String clipboardGetText();
-    public void clipboardSetText(String string);
-
-}
-
-
-class SDLClipboardHandler_API11 implements
-    SDLClipboardHandler,
-    android.content.ClipboardManager.OnPrimaryClipChangedListener {
+class SDLClipboardHandler implements
+    ClipboardManager.OnPrimaryClipChangedListener {
 
-    protected android.content.ClipboardManager mClipMgr;
+    protected ClipboardManager mClipMgr;
 
-    SDLClipboardHandler_API11() {
-       mClipMgr = (android.content.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+    SDLClipboardHandler() {
+       mClipMgr = (ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
        mClipMgr.addPrimaryClipChangedListener(this);
     }
 
-    @Override
     public boolean clipboardHasText() {
-       return mClipMgr.hasText();
+       return mClipMgr.hasPrimaryClip();
     }
 
-    @Override
     public String clipboardGetText() {
-        CharSequence text;
-        text = mClipMgr.getText();
-        if (text != null) {
-           return text.toString();
+        ClipData clip = mClipMgr.getPrimaryClip();
+        if (clip != null) {
+            ClipData.Item item = clip.getItemAt(0);
+            if (item != null) {
+                CharSequence text = item.getText();
+                if (text != null) {
+                    return text.toString();
+                }
+            }
         }
         return null;
     }
 
-    @Override
     public void clipboardSetText(String string) {
        mClipMgr.removePrimaryClipChangedListener(this);
-       mClipMgr.setText(string);
+       ClipData clip = ClipData.newPlainText(null, string);
+       mClipMgr.setPrimaryClip(clip);
        mClipMgr.addPrimaryClipChangedListener(this);
     }
 
@@ -2321,6 +2324,5 @@ class SDLClipboardHandler_API11 implements
     public void onPrimaryClipChanged() {
         SDLActivity.onNativeClipboardChanged();
     }
-
 }
 
index 0714419c2925a4a08e8ce406a414bc3ead78868c..2bfc71860900556ce0ac1481e7162d2d216cb706 100644 (file)
@@ -1,6 +1,10 @@
 package org.libsdl.app;
 
-import android.media.*;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.AudioTrack;
+import android.media.MediaRecorder;
 import android.os.Build;
 import android.util.Log;
 
@@ -43,6 +47,10 @@ public class SDLAudioManager
             if (desiredChannels > 2) {
                 desiredChannels = 2;
             }
+        }
+
+        /* AudioTrack has sample rate limitation of 48000 (fixed in 5.0.2) */
+        if (Build.VERSION.SDK_INT < 22) {
             if (sampleRate < 8000) {
                 sampleRate = 8000;
             } else if (sampleRate > 48000) {
@@ -199,7 +207,6 @@ public class SDLAudioManager
             results[0] = mAudioRecord.getSampleRate();
             results[1] = mAudioRecord.getAudioFormat();
             results[2] = mAudioRecord.getChannelCount();
-            results[3] = desiredFrames;
 
         } else {
             if (mAudioTrack == null) {
@@ -223,8 +230,8 @@ public class SDLAudioManager
             results[0] = mAudioTrack.getSampleRate();
             results[1] = mAudioTrack.getAudioFormat();
             results[2] = mAudioTrack.getChannelCount();
-            results[3] = desiredFrames;
         }
+        results[3] = desiredFrames;
 
         Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", got " + results[3] + " frames of " + results[2] + " channel " + getAudioFormatString(results[1]) + " audio at " + results[0] + " Hz");
 
index a81e97bee84c1173c8f28ef7edf237a8be3e120f..05e0f0cac7e724409b8e9f8d717cdca1839094a2 100644 (file)
@@ -6,9 +6,14 @@ import java.util.Comparator;
 import java.util.List;
 
 import android.content.Context;
-import android.os.*;
-import android.view.*;
+import android.os.Build;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
 import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
 
 
 public class SDLControllerManager
@@ -98,7 +103,7 @@ public class SDLControllerManager
         int sources = device.getSources();
 
         /* This is called for every button press, so let's not spam the logs */
-        /**
+        /*
         if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
             Log.v(TAG, "Input device " + device.getName() + " has class joystick.");
         }
@@ -108,7 +113,7 @@ public class SDLControllerManager
         if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
             Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
         }
-        **/
+        */
 
         return ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ||
                 ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
@@ -167,7 +172,7 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
         }
     }
 
-    private ArrayList<SDLJoystick> mJoysticks;
+    private final ArrayList<SDLJoystick> mJoysticks;
 
     public SDLJoystickHandler_API16() {
 
@@ -177,13 +182,14 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
     @Override
     public void pollInputDevices() {
         int[] deviceIds = InputDevice.getDeviceIds();
-        for(int i=0; i < deviceIds.length; ++i) {
-            SDLJoystick joystick = getJoystick(deviceIds[i]);
-            if (joystick == null) {
-                joystick = new SDLJoystick();
-                InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
-                if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
-                    joystick.device_id = deviceIds[i];
+
+        for (int device_id : deviceIds) {
+            if (SDLControllerManager.isDeviceSDLJoystick(device_id)) {
+                SDLJoystick joystick = getJoystick(device_id);
+                if (joystick == null) {
+                    InputDevice joystickDevice = InputDevice.getDevice(device_id);
+                    joystick = new SDLJoystick();
+                    joystick.device_id = device_id;
                     joystick.name = joystickDevice.getName();
                     joystick.desc = getJoystickDescriptor(joystickDevice);
                     joystick.axes = new ArrayList<InputDevice.MotionRange>();
@@ -191,53 +197,57 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
 
                     List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
                     Collections.sort(ranges, new RangeComparator());
-                    for (InputDevice.MotionRange range : ranges ) {
+                    for (InputDevice.MotionRange range : ranges) {
                         if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
-                            if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
-                                range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                            if (range.getAxis() == MotionEvent.AXIS_HAT_X || range.getAxis() == MotionEvent.AXIS_HAT_Y) {
                                 joystick.hats.add(range);
-                            }
-                            else {
+                            } else {
                                 joystick.axes.add(range);
                             }
                         }
                     }
 
                     mJoysticks.add(joystick);
-                    SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
+                    SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc,
+                            getVendorId(joystickDevice), getProductId(joystickDevice), false,
+                            getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
                 }
             }
         }
 
         /* Check removed devices */
-        ArrayList<Integer> removedDevices = new ArrayList<Integer>();
-        for(int i=0; i < mJoysticks.size(); i++) {
-            int device_id = mJoysticks.get(i).device_id;
-            int j;
-            for (j=0; j < deviceIds.length; j++) {
-                if (device_id == deviceIds[j]) break;
+        ArrayList<Integer> removedDevices = null;
+        for (SDLJoystick joystick : mJoysticks) {
+            int device_id = joystick.device_id;
+            int i;
+            for (i = 0; i < deviceIds.length; i++) {
+                if (device_id == deviceIds[i]) break;
             }
-            if (j == deviceIds.length) {
-                removedDevices.add(Integer.valueOf(device_id));
+            if (i == deviceIds.length) {
+                if (removedDevices == null) {
+                    removedDevices = new ArrayList<Integer>();
+                }
+                removedDevices.add(device_id);
             }
         }
 
-        for(int i=0; i < removedDevices.size(); i++) {
-            int device_id = removedDevices.get(i).intValue();
-            SDLControllerManager.nativeRemoveJoystick(device_id);
-            for (int j=0; j < mJoysticks.size(); j++) {
-                if (mJoysticks.get(j).device_id == device_id) {
-                    mJoysticks.remove(j);
-                    break;
+        if (removedDevices != null) {
+            for (int device_id : removedDevices) {
+                SDLControllerManager.nativeRemoveJoystick(device_id);
+                for (int i = 0; i < mJoysticks.size(); i++) {
+                    if (mJoysticks.get(i).device_id == device_id) {
+                        mJoysticks.remove(i);
+                        break;
+                    }
                 }
             }
         }
     }
 
     protected SDLJoystick getJoystick(int device_id) {
-        for(int i=0; i < mJoysticks.size(); i++) {
-            if (mJoysticks.get(i).device_id == device_id) {
-                return mJoysticks.get(i);
+        for (SDLJoystick joystick : mJoysticks) {
+            if (joystick.device_id == device_id) {
+                return joystick;
             }
         }
         return null;
@@ -248,25 +258,21 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
         if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
             int actionPointerIndex = event.getActionIndex();
             int action = event.getActionMasked();
-            switch(action) {
-                case MotionEvent.ACTION_MOVE:
-                    SDLJoystick joystick = getJoystick(event.getDeviceId());
-                    if ( joystick != null ) {
-                        for (int i = 0; i < joystick.axes.size(); i++) {
-                            InputDevice.MotionRange range = joystick.axes.get(i);
-                            /* Normalize the value to -1...1 */
-                            float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
-                            SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
-                        }
-                        for (int i = 0; i < joystick.hats.size(); i+=2) {
-                            int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
-                            int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
-                            SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
-                        }
+            if (action == MotionEvent.ACTION_MOVE) {
+                SDLJoystick joystick = getJoystick(event.getDeviceId());
+                if (joystick != null) {
+                    for (int i = 0; i < joystick.axes.size(); i++) {
+                        InputDevice.MotionRange range = joystick.axes.get(i);
+                        /* Normalize the value to -1...1 */
+                        float value = (event.getAxisValue(range.getAxis(), actionPointerIndex) - range.getMin()) / range.getRange() * 2.0f - 1.0f;
+                        SDLControllerManager.onNativeJoy(joystick.device_id, i, value);
+                    }
+                    for (int i = 0; i < joystick.hats.size() / 2; i++) {
+                        int hatX = Math.round(event.getAxisValue(joystick.hats.get(2 * i).getAxis(), actionPointerIndex));
+                        int hatY = Math.round(event.getAxisValue(joystick.hats.get(2 * i + 1).getAxis(), actionPointerIndex));
+                        SDLControllerManager.onNativeHat(joystick.device_id, i, hatX, hatY);
                     }
-                    break;
-                default:
-                    break;
+                }
             }
         }
         return true;
@@ -432,13 +438,13 @@ class SDLHapticHandler_API26 extends SDLHapticHandler {
 
 class SDLHapticHandler {
 
-    class SDLHaptic {
+    static class SDLHaptic {
         public int device_id;
         public String name;
         public Vibrator vib;
     }
 
-    private ArrayList<SDLHaptic> mHaptics;
+    private final ArrayList<SDLHaptic> mHaptics;
 
     public SDLHapticHandler() {
         mHaptics = new ArrayList<SDLHaptic>();
@@ -504,37 +510,41 @@ class SDLHapticHandler {
         }
 
         /* Check removed devices */
-        ArrayList<Integer> removedDevices = new ArrayList<Integer>();
-        for(int i=0; i < mHaptics.size(); i++) {
-            int device_id = mHaptics.get(i).device_id;
-            int j;
-            for (j=0; j < deviceIds.length; j++) {
-                if (device_id == deviceIds[j]) break;
+        ArrayList<Integer> removedDevices = null;
+        for (SDLHaptic haptic : mHaptics) {
+            int device_id = haptic.device_id;
+            int i;
+            for (i = 0; i < deviceIds.length; i++) {
+                if (device_id == deviceIds[i]) break;
             }
 
-            if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
-                // don't remove the vibrator if it is still present
-            } else if (j == deviceIds.length) {
-                removedDevices.add(device_id);
-            }
+            if (device_id != deviceId_VIBRATOR_SERVICE || !hasVibratorService) {
+                if (i == deviceIds.length) {
+                    if (removedDevices == null) {
+                        removedDevices = new ArrayList<Integer>();
+                    }
+                    removedDevices.add(device_id);
+                }
+            }  // else: don't remove the vibrator if it is still present
         }
 
-        for(int i=0; i < removedDevices.size(); i++) {
-            int device_id = removedDevices.get(i);
-            SDLControllerManager.nativeRemoveHaptic(device_id);
-            for (int j=0; j < mHaptics.size(); j++) {
-                if (mHaptics.get(j).device_id == device_id) {
-                    mHaptics.remove(j);
-                    break;
+        if (removedDevices != null) {
+            for (int device_id : removedDevices) {
+                SDLControllerManager.nativeRemoveHaptic(device_id);
+                for (int i = 0; i < mHaptics.size(); i++) {
+                    if (mHaptics.get(i).device_id == device_id) {
+                        mHaptics.remove(i);
+                        break;
+                    }
                 }
             }
         }
     }
 
     protected SDLHaptic getHaptic(int device_id) {
-        for(int i=0; i < mHaptics.size(); i++) {
-            if (mHaptics.get(i).device_id == device_id) {
-                return mHaptics.get(i);
+        for (SDLHaptic haptic : mHaptics) {
+            if (haptic.device_id == device_id) {
+                return haptic;
             }
         }
         return null;
@@ -655,8 +665,7 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
     public float getEventX(MotionEvent event) {
         if (mRelativeModeEnabled) {
             return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
-        }
-        else {
+        } else {
             return event.getX(0);
         }
     }
@@ -665,14 +674,12 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
     public float getEventY(MotionEvent event) {
         if (mRelativeModeEnabled) {
             return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
-        }
-        else {
+        } else {
             return event.getY(0);
         }
     }
 }
 
-
 class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
     // Generic Motion (mouse hover, joystick...) events go here
     private boolean mRelativeModeEnabled;
@@ -753,15 +760,12 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
         if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
             if (enabled) {
                 SDLActivity.getContentView().requestPointerCapture();
-            }
-            else {
+            } else {
                 SDLActivity.getContentView().releasePointerCapture();
             }
             mRelativeModeEnabled = enabled;
             return true;
-        }
-        else
-        {
+        } else {
             return false;
         }
     }
index 9ed04d0faba356c248afb6336d6d79d6139c69c7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
Binary files a/build-projects/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/build-projects/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
index bf733ec582ae2a7d2474a87b473eaebc22e3359b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
Binary files a/build-projects/android/app/src/main/res/mipmap-ldpi/ic_launcher.png and b/build-projects/android/app/src/main/res/mipmap-ldpi/ic_launcher.png differ
index 560306ac8c94f60177f43a6ea30898dfaa578340..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
Binary files a/build-projects/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/build-projects/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
index 4c31ddeb3d2cf59fc944019dea2c07103d8cfb49..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
Binary files a/build-projects/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/build-projects/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
index 132d3c1302e8760f1a6e03e7afb68d602ef20564..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
Binary files a/build-projects/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/build-projects/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
index f6f90b25b17cc5f48f54e521b3e000b9153fea11..6f629c8aa758ef8e81514ab2fb4fe81623db19c0 100644 (file)
@@ -2,11 +2,11 @@
 
 buildscript {
     repositories {
-        jcenter()
+        mavenCentral()
         google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.2.0'
+        classpath 'com.android.tools.build:gradle:7.0.3'
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
@@ -15,7 +15,7 @@ buildscript {
 
 allprojects {
     repositories {
-        jcenter()
+        mavenCentral()
         google()
     }
 }
index f9b3be2f9fbfc146492000cfb2818c399b17138b..674589313b294ee728275ab89208cf2c9a9d2c5e 100644 (file)
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
diff --git a/build-projects/emscripten/favicon-16x16.png b/build-projects/emscripten/favicon-16x16.png
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/emscripten/favicon-32x32.png b/build-projects/emscripten/favicon-32x32.png
new file mode 100644 (file)
index 0000000..e69de29
index cdf397f514aa16e298301131597ff4bd4a2c0948..a4d0d975b6117bc27a522e6b84d031e034381b93 100644 (file)
@@ -3,16 +3,47 @@
 <head>
 <meta charset="utf-8"><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <title>Loading Rocks'n'Diamonds</title>
+<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32">
+<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16">
+<style>
+body {
+    background: black;
+    text-align: center;
+    vertical-align: middle;
+}
+#loading {
+    color: white;
+    font-size: 120%;
+    font-family: sans-serif;
+}
+#canvas {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    margin: 0px;
+    width: 100%;
+    height: 100%;
+    overflow: hidden;
+    display: block;
+}
+</style>
 </head>
-<body style="background:black;text-align:center;vertical-align:middle;">
+<body>
 <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
+<div id="loading">
+<img src="loading.svg" width="200px" height="200px">
+<br>
+Loading Rocks'n'Diamonds ...
+</div>
 <script type='text/javascript'>
       var Module = {
         arguments: [],
         preRun: [
           function() {}
         ],
-        postRun: [],
+        postRun: [
+          function() { loading.style.display = 'none'; }
+        ],
         print: (function() {
           var element = document.getElementById('output');
           if (element) element.value = ''; // clear browser cache
@@ -50,7 +81,8 @@
         alert("An error occurred, see console.");
         document.title = "Rocks'n'Diamonds (aborted)";
       };
-    </script>
+</script>
+<script async type="text/javascript" src="rocksndiamonds.data.js"></script>
 <script async type="text/javascript" src="rocksndiamonds.js"></script>
 </body>
 </html>
diff --git a/build-projects/emscripten/loading.svg b/build-projects/emscripten/loading.svg
new file mode 100644 (file)
index 0000000..5ca45ca
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto; animation-play-state: running; animation-delay: 0s;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
+<g transform="rotate(0 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.9166666666666666s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(30 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.8333333333333334s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(60 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.75s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(90 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.6666666666666666s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(120 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5833333333333334s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(150 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.5s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(180 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.4166666666666667s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(210 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.3333333333333333s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(240 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.25s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(270 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.16666666666666666s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(300 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="-0.08333333333333333s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g><g transform="rotate(330 50 50)" style="animation-play-state: running; animation-delay: 0s;">
+  <rect x="48.5" y="24.5" rx="1.5" ry="1.98" width="3" height="11" fill="#ffffff" style="animation-play-state: running; animation-delay: 0s;">
+    <animate attributeName="opacity" values="1;0" keyTimes="0;1" dur="1s" begin="0s" repeatCount="indefinite" style="animation-play-state: running; animation-delay: 0s;"></animate>
+  </rect>
+</g>
+<!-- [ldio] generated by https://loading.io/ --></svg>
diff --git a/build-projects/mac/Rocks'n'Diamonds.app/Contents/Frameworks/.gitkeep b/build-projects/mac/Rocks'n'Diamonds.app/Contents/Frameworks/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/mac/Rocks'n'Diamonds.app/Contents/Info.plist.template b/build-projects/mac/Rocks'n'Diamonds.app/Contents/Info.plist.template
new file mode 100644 (file)
index 0000000..9f98db3
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>rocksndiamonds</string>
+       <key>CFBundleIconFile</key>
+       <string>rocksndiamonds.icns</string>
+       <key>CFBundleIdentifier</key>
+       <string>org.artsoft.rocksndiamonds</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>Rocks'n'Diamonds</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>__VERSION__</string>
+       <key>NSHumanReadableCopyright</key>
+       <string>Copyright (c) 1995-__YEAR__ by Artsoft Entertainment</string>
+</dict>
+</plist>
diff --git a/build-projects/mac/Rocks'n'Diamonds.app/Contents/MacOS/.gitkeep b/build-projects/mac/Rocks'n'Diamonds.app/Contents/MacOS/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/mac/Rocks'n'Diamonds.app/Contents/PkgInfo b/build-projects/mac/Rocks'n'Diamonds.app/Contents/PkgInfo
new file mode 100644 (file)
index 0000000..bd04210
--- /dev/null
@@ -0,0 +1 @@
+APPL????
\ No newline at end of file
diff --git a/build-projects/mac/Rocks'n'Diamonds.app/Contents/Resources/rocksndiamonds.icns b/build-projects/mac/Rocks'n'Diamonds.app/Contents/Resources/rocksndiamonds.icns
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/windows/icons/icon-128x128.png b/build-projects/windows/icons/icon-128x128.png
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/windows/icons/icon-16x16.png b/build-projects/windows/icons/icon-16x16.png
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/windows/icons/icon-32x32.png b/build-projects/windows/icons/icon-32x32.png
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/windows/icons/icon-48x48.png b/build-projects/windows/icons/icon-48x48.png
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/build-projects/windows/rocksndiamonds.url b/build-projects/windows/rocksndiamonds.url
new file mode 100644 (file)
index 0000000..6eb9635
--- /dev/null
@@ -0,0 +1,2 @@
+[InternetShortcut]
+URL=https://www.artsoft.org/rocksndiamonds/
diff --git a/build-projects/windows/template.iss b/build-projects/windows/template.iss
new file mode 100644 (file)
index 0000000..5de9476
--- /dev/null
@@ -0,0 +1,53 @@
+; =============================================================================\r
+; template.iss\r
+; -----------------------------------------------------------------------------\r
+; configuration template for Inno Setup installation project\r
+;\r
+; 2020-06-30 info@artsoft.org\r
+; =============================================================================\r
+\r
+[Setup]\r
+AppName=_PRG_NAME_\r
+AppVerName=_PRG_NAME_ _PRG_VERSION_\r
+AppPublisher=Artsoft Entertainment\r
+AppPublisherURL=https://www.artsoft.org/\r
+AppSupportURL=https://www.artsoft.org/_PRG_BASENAME_/\r
+AppUpdatesURL=https://www.artsoft.org/_PRG_BASENAME_/\r
+\r
+ArchitecturesInstallIn64BitMode=_PRG_ARCH_\r
+ArchitecturesAllowed=_PRG_ARCH_\r
+\r
+DefaultDirName={pf}\_PRG_NAME_\r
+DefaultGroupName=_PRG_NAME_\r
+;LicenseFile="_PRG_DIR_\COPYING.txt"\r
+;InfoBeforeFile="_PRG_DIR_\INSTALL.txt"\r
+;InfoAfterFile="_PRG_DIR_\README.txt"\r
+UninstallDisplayIcon={app}\_PRG_EXE_\r
+Compression=lzma\r
+SolidCompression=yes\r
+\r
+OutputBaseFilename=_SETUP_EXE_\r
+OutputDir=.\r
+\r
+[Files]\r
+Source: "_PRG_DIR_\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ignoreversion\r
+\r
+[Tasks]\r
+Name: "desktopicon"; Description: "Create a &Desktop icon"; GroupDescription: "Additional icons:"\r
+Name: "quicklaunchicon"; Description: "Create a &Quick Launch icon"; GroupDescription: "Additional icons:"\r
+\r
+[Icons]\r
+Name: "{group}\_PRG_NAME_"; Filename: "{app}\_PRG_EXE_"\r
+Name: "{group}\_PRG_NAME_ on the Web"; Filename: "{app}\_PRG_BASENAME_.url"\r
+Name: "{userdesktop}\_PRG_NAME_"; Filename: "{app}\_PRG_EXE_"; Tasks: desktopicon\r
+Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\_PRG_NAME_"; Filename: "{app}\_PRG_EXE_"; Tasks: quicklaunchicon\r
+\r
+; This dynamically generates a Windows internet shortcut file. Unfortunately,\r
+; this file is not removed when the package is uninstalled, leaving an empty\r
+; program directory with just that internet shortcut file. Using a static file\r
+; does not cause this problem.\r
+;[INI]\r
+;Filename: "{app}\_PRG_BASENAME_.url"; Section: "InternetShortcut"; Key: "URL"; String: "https://www.artsoft.org/_PRG_BASENAME_/"\r
+\r
+[Run]\r
+Filename: "{app}\_PRG_EXE_"; Description: "Launch _PRG_NAME_"; Flags: nowait postinstall skipifsilent\r
index 0966816ae3e717a7ba273942a36899ea2aaaf82c..08d4e946f2c5ebff89cd2ec93724a839d6be19f6 100755 (executable)
@@ -42,6 +42,8 @@ my $filename_conf_cus_c = 'conf_cus.c';
 my $filename_conf_cus_h = 'conf_cus.h';
 my $filename_conf_grp_c = 'conf_grp.c';
 my $filename_conf_grp_h = 'conf_grp.h';
+my $filename_conf_emp_c = 'conf_emp.c';
+my $filename_conf_emp_h = 'conf_emp.h';
 my $filename_conf_e2g_c = 'conf_e2g.c';
 my $filename_conf_esg_c = 'conf_esg.c';
 my $filename_conf_e2s_c = 'conf_e2s.c';
@@ -61,17 +63,20 @@ my $text_cus_c = 'values for graphics configuration (custom elements)';
 my $text_cus_h = 'values for elements configuration (custom elements)';
 my $text_grp_c = 'values for graphics configuration (group elements)';
 my $text_grp_h = 'values for elements configuration (group elements)';
+my $text_emp_c = 'values for graphics configuration (empty elements)';
+my $text_emp_h = 'values for elements configuration (empty elements)';
 my $text_e2g_c = 'values for element/graphics mapping configuration (normal)';
 my $text_esg_c = 'values for element/graphics mapping configuration (special)';
 my $text_e2s_c = 'values for element/sounds mapping configuration';
 my $text_fnt_c = 'values for font/graphics mapping configuration';
 my $text_g2s_c = 'values for gamemode/sound mapping configuration';
 my $text_g2m_c = 'values for gamemode/music mapping configuration';
-my $text_var_c = 'values for image and layout parameter configuration';
+my $text_var_c = 'values for graphics and sound parameter configuration';
 my $text_act_c = 'values for active states of elements and fonts';
 
 my $num_custom_elements = 256;
 my $num_group_elements = 32;
+my $num_empty_elements = 16;
 
 my $char_skip = '---[SKIP]---';
 
@@ -393,6 +398,28 @@ sub print_graphics_list
            }
        }
 
+       if (/^\#include "conf_emp.c"/)  # dump list of empty elements
+       {
+           for (my $nr = 0; $nr < $num_empty_elements; $nr++)
+           {
+               my $line = sprintf("#define IMG_EMPTY_SPACE_%d", $nr + 1);
+
+               my $tabs = get_tabs($line, $max_num_tabs);
+
+               print "$line$tabs$i\n";
+
+               $i++;
+
+               $line = sprintf("#define IMG_EMPTY_SPACE_%d_EDITOR", $nr + 1);
+
+               $tabs = get_tabs($line, $max_num_tabs);
+
+               print "$line$tabs$i\n";
+
+               $i++;
+           }
+       }
+
        if (!contains_image_file($_))   # skip all lines without image file
        {
            next;
@@ -473,6 +500,11 @@ sub print_sounds_list
            $sound =~ s/^/CLASS_/;      # add class identifier
        }
 
+       # dirty hack for making "ABC[DEF]" work as a "special" suffix
+       $sound =~ s/([^_])\[/$1_/;
+       $sound =~ s/\[//;
+       $sound =~ s/\]//;
+
        $sound = "SND_$sound";
 
        my $define_text = "#define $sound";
@@ -531,6 +563,11 @@ sub print_music_list
 
        my $music = $_;
 
+       # dirty hack for making "ABC[DEF]" work as a "special" suffix
+       $music =~ s/([^_])\[/$1_/;
+       $music =~ s/\[//;
+       $music =~ s/\]//;
+
        $music = "MUS_$music";
 
        my $define_text = "#define $music";
@@ -727,6 +764,24 @@ sub print_group_elements_list
     print_file_footer($filename_conf_grp_c);
 }
 
+sub print_empty_elements_list
+{
+    print_file_header($filename_conf_emp_h, $text_emp_h);
+
+    for (my $i = 0; $i < $num_empty_elements; $i++)
+    {
+       my $left = sprintf("#define EL_EMPTY_SPACE_%d", $i + 1);
+
+       my $tabs_left = get_tabs($left, 5);
+
+       my $right = "(EL_EMPTY_SPACE_START + $i)";
+
+       print "$left$tabs_left$right\n";
+    }
+
+    print_file_footer($filename_conf_emp_c);
+}
+
 sub print_custom_graphics_list
 {
     my @extensions1 =
@@ -889,6 +944,89 @@ sub print_group_graphics_list
     print_file_footer($filename_conf_grp_c);
 }
 
+sub print_empty_graphics_list
+{
+    my @extensions1 =
+       (
+        '',
+        '.xpos',
+        '.ypos',
+        '.frames',
+        );
+    my @extensions2 =
+       (
+        '',
+        '.xpos',
+        '.ypos',
+        );
+
+    my $num_non_empty_elements = $num_custom_elements + $num_group_elements;
+
+    print_file_header($filename_conf_emp_c, $text_emp_c);
+
+    for (my $i = 0; $i < $num_empty_elements; $i++)
+    {
+       foreach my $ext (@extensions1)
+       {
+           my $left = sprintf("  \{ \"empty_space_%d$ext\",", $i + 1);
+
+           my $tabs_left = get_tabs($left, 6);
+
+           # my $right = ($ext eq '' ? 'RocksDC.png' :
+           my $right = ($ext eq '' ? 'RocksCE.png' :
+                        $ext eq '.frames' ? '1' : '0');
+
+           if ($ext eq '.xpos')
+           {
+               # $right = 4;
+               $right = int($i % 16);
+           }
+           elsif ($ext eq '.ypos')
+           {
+               # $right = 15;
+               $right = int($i / 16) + int($num_non_empty_elements / 16);
+           }
+
+           $right = "\"$right\"";
+
+           my $tabs_right = get_tabs($right, 3);
+
+           print "$left$tabs_left$right$tabs_right},\n";
+       }
+
+       foreach my $ext (@extensions2)
+       {
+           my $left = sprintf("  \{ \"empty_space_%d.EDITOR$ext\",", $i + 1);
+
+           my $tabs_left = get_tabs($left, 6);
+
+           # my $right = ($ext eq '' ? 'RocksDC.png' : '0');
+           my $right = ($ext eq '' ? 'RocksCE.png' : '0');
+
+           if ($ext eq '.xpos')
+           {
+               # $right = 14;
+               $right = int($i % 16) + 16;
+           }
+           elsif ($ext eq '.ypos')
+           {
+               # $right = 15;
+               $right = int($i / 16) + int($num_non_empty_elements / 16);
+           }
+
+           $right = "\"$right\"";
+
+           my $tabs_right = get_tabs($right, 3);
+
+           print "$left$tabs_left$right$tabs_right},\n";
+       }
+
+       print "\n";
+    }
+
+    print_file_footer($filename_conf_emp_c);
+}
+
 sub get_known_element_definitions_ALTERNATIVE
 {
     my %known_element = ();
@@ -1317,7 +1455,7 @@ sub print_gamemode_to_music_entry
     print "  },\n";
 }
 
-sub print_image_config_var_entry
+sub print_config_var_entry
 {
     my ($token, $var) = @_;
 
@@ -1644,6 +1782,15 @@ sub print_element_to_graphic_list
        print_element_to_graphic_entry($element, '-1', '-1', '-1', $graphic);
     }
 
+    # dump list of empty elements
+    for (my $i = 0; $i < $num_empty_elements; $i++)
+    {
+       my $element = sprintf("EL_EMPTY_SPACE_%d", $i + 1);
+       my $graphic = sprintf("IMG_EMPTY_SPACE_%d", $i + 1);
+
+       print_element_to_graphic_entry($element, '-1', '-1', '-1', $graphic);
+    }
+
     print_element_to_graphic_entry('-1', '-1', '-1', '-1', '-1');
 
     print "};\n";
@@ -1815,6 +1962,17 @@ sub print_element_to_special_graphic_list
                                               $graphic);
     }
 
+    # dump list of empty element editor graphics
+    for (my $i = 0; $i < $num_empty_elements; $i++)
+    {
+       my $element = sprintf("EL_EMPTY_SPACE_%d", $i + 1);
+       my $graphic = sprintf("IMG_EMPTY_SPACE_%d_EDITOR", $i + 1);
+
+       print_element_to_special_graphic_entry($element,
+                                              'GFX_SPECIAL_ARG_EDITOR',
+                                              $graphic);
+    }
+
     # dump other special editor graphics
     foreach my $token (@elements_with_editor_graphic)
     {
@@ -2322,7 +2480,7 @@ sub print_gamemode_to_music_list
     print_file_footer($filename_conf_g2m_c);
 }
 
-sub print_image_config_vars
+sub print_config_vars
 {
     # ---------- read graphic file definitions ----------
 
@@ -2361,6 +2519,7 @@ sub print_image_config_vars
 
            $var =~ s/^main\./menu.main./;
            $var =~ s/^setup\./menu.setup./;
+           $var =~ s/^scores\./menu.scores./;
            $var =~ s/^\[player\]\./game.player_/;
            $var =~ s/^\[title_initial\]/title_initial_default/;
            $var =~ s/^\[title\]/title_default/;
@@ -2428,7 +2587,7 @@ sub print_image_config_vars
                $var = $1 . "[GFX_SPECIAL_ARG_DEFAULT]" . $3;
            }
 
-           print_image_config_var_entry("\"$token\"", "&$var");
+           print_config_var_entry("\"$token\"", "&$var");
 
            if ($var =~ /^(title)_default/ ||
                $var =~ /^(title_initial)_default/ ||
@@ -2438,12 +2597,54 @@ sub print_image_config_vars
                my $prefix = $1;
                $var =~ s/^$prefix/${prefix}_first/;
 
-               print_image_config_var_entry("\"$token\"", "&$var");
+               print_config_var_entry("\"$token\"", "&$var");
            }
        }
     }
 
-    print_image_config_var_entry('NULL', 'NULL');
+    print_config_var_entry('NULL', 'NULL');
+
+    print "};\n";
+
+    close FILE;
+
+
+    # ---------- read sound file definitions ----------
+
+    $filename = "$src_path/conf_snd.c";
+
+    open(FILE, "$filename") ||
+       fail("cannot open file '$filename' for reading");
+
+    print "struct TokenIntPtrInfo sound_config_vars[] =\n";
+    print "{\n";
+
+    $start_parsing = 0;
+
+    while (<FILE>)
+    {
+       chomp;                          # cut trailing newline
+
+       if (/CONFIG_VARS_START/)        # keyword to start parsing file
+       {
+           $start_parsing = 1;
+       }
+
+       if (!$start_parsing)
+       {
+           next;
+       }
+
+       if (/^\s*\{\s*\"([^\"]+)\"/)    # config token found
+       {
+           my $token = $1;
+           my $var = $token;
+
+           print_config_var_entry("\"$token\"", "&$var");
+       }
+    }
+
+    print_config_var_entry('NULL', 'NULL');
 
     print "};\n";
 
@@ -2557,6 +2758,8 @@ sub main
        print "- '$filename_conf_cus_h'\n";
        print "- '$filename_conf_grp_c'\n";
        print "- '$filename_conf_grp_h'\n";
+       print "- '$filename_conf_emp_c'\n";
+       print "- '$filename_conf_emp_h'\n";
        print "- '$filename_conf_e2g_c'\n";
        print "- '$filename_conf_esg_c'\n";
        print "- '$filename_conf_fnt_c'\n";
@@ -2604,6 +2807,14 @@ sub main
     {
        print_group_elements_list();
     }
+    elsif ($ARGV[0] eq $filename_conf_emp_c)
+    {
+       print_empty_graphics_list();
+    }
+    elsif ($ARGV[0] eq $filename_conf_emp_h)
+    {
+       print_empty_elements_list();
+    }
     elsif ($ARGV[0] eq $filename_conf_e2g_c)
     {
        print_element_to_graphic_list();
@@ -2630,7 +2841,7 @@ sub main
     }
     elsif ($ARGV[0] eq $filename_conf_var_c)
     {
-       print_image_config_vars();
+       print_config_vars();
     }
     elsif ($ARGV[0] eq $filename_conf_act_c)
     {
diff --git a/docs/credits/credits_1.txt b/docs/credits/credits_1.txt
new file mode 100644 (file)
index 0000000..52c2653
--- /dev/null
@@ -0,0 +1,23 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Peter Liepa
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"Boulder Dash"
+
+# .font: font.text_2
+in the year
+
+# .font: font.text_3
+1984
+
+# .font: font.text_2
+published by
+
+# .font: font.text_3
+First Star Software
diff --git a/docs/credits/credits_10.txt b/docs/credits/credits_10.txt
new file mode 100644 (file)
index 0000000..d14c2fc
--- /dev/null
@@ -0,0 +1,9 @@
+# .font: font.text_2
+And not to forget:
+
+Many thanks to
+
+# .font: font.text_3
+All those who contributed
+levels to this game
+since 1995
diff --git a/docs/credits/credits_2.txt b/docs/credits/credits_2.txt
new file mode 100644 (file)
index 0000000..801241a
--- /dev/null
@@ -0,0 +1,23 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Klaus Heinz & Volker Wertich
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"Emerald Mine"
+
+# .font: font.text_2
+in the year
+
+# .font: font.text_3
+1987
+
+# .font: font.text_2
+published by
+
+# .font: font.text_3
+Kingsoft
diff --git a/docs/credits/credits_3.txt b/docs/credits/credits_3.txt
new file mode 100644 (file)
index 0000000..53b6127
--- /dev/null
@@ -0,0 +1,23 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Michael Stopp & Philip Jespersen
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"Supaplex"
+
+# .font: font.text_2
+in the year
+
+# .font: font.text_3
+1991
+
+# .font: font.text_2
+published by
+
+# .font: font.text_3
+Digital Integration
diff --git a/docs/credits/credits_4.txt b/docs/credits/credits_4.txt
new file mode 100644 (file)
index 0000000..33ca68d
--- /dev/null
@@ -0,0 +1,23 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Hiroyuki Imabayashi
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"Sokoban"
+
+# .font: font.text_2
+in the year
+
+# .font: font.text_3
+1982
+
+# .font: font.text_2
+published by
+
+# .font: font.text_3
+Thinking Rabbit
diff --git a/docs/credits/credits_5.txt b/docs/credits/credits_5.txt
new file mode 100644 (file)
index 0000000..8fd61c3
--- /dev/null
@@ -0,0 +1,15 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Alan Bond
+
+# .font: font.text_2
+and
+
+# .font: font.text_3
+Jürgen Bonhagen
+
+# .font: font.text_2
+for the continuous creation
+of outstanding level sets
diff --git a/docs/credits/credits_6.txt b/docs/credits/credits_6.txt
new file mode 100644 (file)
index 0000000..7c366cb
--- /dev/null
@@ -0,0 +1,25 @@
+# .font: font.text_2
+Thanks to
+
+# .font: font.text_3
+Peter Elzner
+
+# .font: font.text_2
+for ideas and inspiration by
+
+# .font: font.text_3
+"Diamond Caves"
+
+
+
+# .font: font.text_2
+Thanks to
+
+# .font: font.text_3
+Steffest
+
+# .font: font.text_2
+for ideas and inspiration by
+
+# .font: font.text_3
+"DX-Boulderdash"
diff --git a/docs/credits/credits_7.txt b/docs/credits/credits_7.txt
new file mode 100644 (file)
index 0000000..ee5f8fb
--- /dev/null
@@ -0,0 +1,33 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Czirkos Zoltan
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"GDash"
+
+# .font: font.text_2
+used for the
+native Boulder Dash engine
+
+
+
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+David Tritscher
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"Emerald Mine for X11"
+
+# .font: font.text_2
+used for the
+native Emerald Mine engine
diff --git a/docs/credits/credits_8.txt b/docs/credits/credits_8.txt
new file mode 100644 (file)
index 0000000..ae33247
--- /dev/null
@@ -0,0 +1,26 @@
+# .font: font.text_2
+Special thanks to
+
+# .font: font.text_3
+Frank Schindler
+
+# .font: font.text_2
+for creating
+
+# .font: font.text_3
+"MegaPlex"
+
+# .font: font.text_2
+used for the
+native Supaplex engine
+
+
+
+# .font: font.text_2
+Thanks to
+
+# .font: font.text_3
+Guido Schulz
+
+# .font: font.text_2
+for the initial DOS/Windows port
diff --git a/docs/credits/credits_9.txt b/docs/credits/credits_9.txt
new file mode 100644 (file)
index 0000000..8482f06
--- /dev/null
@@ -0,0 +1,25 @@
+# .font: font.text_2
+Thanks to
+
+# .font: font.text_3
+Thomas Andrae
+
+# .font: font.text_2
+and
+
+# .font: font.text_3
+Karl Hörnell
+
+# .font: font.text_2
+for additional toon animations
+
+
+
+# .font: font.text_2
+Thanks to
+
+# .font: font.text_3
+Majid Katzer
+
+# .font: font.text_2
+for additional sounds and music
diff --git a/docs/elements/bd_expandable_wall.txt b/docs/elements/bd_expandable_wall.txt
new file mode 100644 (file)
index 0000000..1f77835
--- /dev/null
@@ -0,0 +1,6 @@
+This wall will grow on either side that is open. It will stop
+growing on one side if it is blocked by a wall, even if said wall is later
+destroyed. Gems and others, however, will stop it only temporarily.
+
+This particular growing wall is the only one that is visibly different
+to the player from a normal wall, at least under the default graphics.
index 3800be9e1080fe5dd7c9bed876e605332b0fb286..475d1103601664dd90b484bb189ab899f496aac4 100644 (file)
@@ -1,7 +1,8 @@
-This is a (BD style) magic wall. It gets activated for about 10 seconds by
-rocks or gems that fall on it. Rocks that fall through it become BD style
-diamonds, and gems that fall through it become BD style rocks. After it has
-stopped running, it cannot be activated again.
+This is a BD style magic wall. It gets activated for a limited duration by
+rocks or gems that fall on it. While activated, they can fall through it, and
+rocks turn into BD style diamonds, and gems turn into BD style rocks.
+After the magic wall has stopped running, it cannot be activated again.
 
-All BD magic walls run on the same timer; however, regular magic walls run
-on a seperate timer.
+The duration in seconds for which magic walls are active is configurable.
+A duration of zero will let the wall run forever.
+All magic walls share the same timer.
diff --git a/docs/elements/bdx_acid.txt b/docs/elements/bdx_acid.txt
new file mode 100644 (file)
index 0000000..fd41985
--- /dev/null
@@ -0,0 +1,2 @@
+Acid eats sand. Sometimes it spreads in all four directions, leaving a small
+explosion behind. If there is no sand to swallow, it just disappears.
diff --git a/docs/elements/bdx_amoeba.txt b/docs/elements/bdx_amoeba.txt
new file mode 100644 (file)
index 0000000..f167336
--- /dev/null
@@ -0,0 +1,5 @@
+Amoebas grow randomly through empty space and sand. When enclosed, they stop
+growing and transform into diamonds (or some other, configurable game element).
+
+When grown too big, they suddenly transform into rocks. At the beginning,
+they can grow slowly, but after some time they start growing very rapidly.
diff --git a/docs/elements/bdx_amoeba_1.txt b/docs/elements/bdx_amoeba_1.txt
new file mode 100644 (file)
index 0000000..8df48da
--- /dev/null
@@ -0,0 +1,6 @@
+The amoeba (first variant) grows randomly through empty space and sand.
+When it is enclosed, it stops growing and transforms into diamonds (or
+some other, configurable game element).
+
+When it has grown too big, it suddenly transforms into rocks. At the beginning,
+it can grow slowly, but after some time it starts growing very rapidly.
diff --git a/docs/elements/bdx_amoeba_2.txt b/docs/elements/bdx_amoeba_2.txt
new file mode 100644 (file)
index 0000000..612f966
--- /dev/null
@@ -0,0 +1,3 @@
+The second variant of the amoeba behaves exactly like the first one.
+But it lives its own life. Sometimes, when they collide, they produce an
+explosion.
diff --git a/docs/elements/bdx_biter.txt b/docs/elements/bdx_biter.txt
new file mode 100644 (file)
index 0000000..6399048
--- /dev/null
@@ -0,0 +1,4 @@
+Biters will eat all the dirt they can reach. They move in a predictable way.
+They can also eat diamonds, so better don't let them be taken away. They will
+move through rocks throwing them behind if there is no space for turning. That
+way, you can get rid of rocks blocking your way.
diff --git a/docs/elements/bdx_biter_switch.txt b/docs/elements/bdx_biter_switch.txt
new file mode 100644 (file)
index 0000000..616f563
--- /dev/null
@@ -0,0 +1 @@
+This switch controls the speed of biters.
diff --git a/docs/elements/bdx_bladder.txt b/docs/elements/bdx_bladder.txt
new file mode 100644 (file)
index 0000000..d4fc834
--- /dev/null
@@ -0,0 +1,2 @@
+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
new file mode 100644 (file)
index 0000000..389a72c
--- /dev/null
@@ -0,0 +1 @@
+If there is space above it, the bladder spender turns to a bladder.
diff --git a/docs/elements/bdx_bomb.txt b/docs/elements/bdx_bomb.txt
new file mode 100644 (file)
index 0000000..c10debf
--- /dev/null
@@ -0,0 +1,3 @@
+You can pick up this bomb like a diamond. To use it, press the snap or drop
+key and a direction... and then quickly run away! You can hold only one bomb
+at a time.
diff --git a/docs/elements/bdx_box.txt b/docs/elements/bdx_box.txt
new file mode 100644 (file)
index 0000000..6f521fd
--- /dev/null
@@ -0,0 +1,3 @@
+Sometimes you have to block a passage, for example to protect a voodoo doll.
+This is when a box like this comes handy. You can push it in every direction
+using the snap or drop key.
diff --git a/docs/elements/bdx_butterfly.txt b/docs/elements/bdx_butterfly.txt
new file mode 100644 (file)
index 0000000..3cf6342
--- /dev/null
@@ -0,0 +1,6 @@
+Butterflies move through empty space. Touching them is deadly.. Butterflies
+blow up when hit by a falling rock or diamond. Amoeba is also deadly for them.
+They explode into diamonds, producing a 3x3 square of diamonds. Butterflies are
+spinning right. They prefer turning right, usually clockwise.
+
+There is another variant of the butterfly that is spinning left.
diff --git a/docs/elements/bdx_chasing_rock.txt b/docs/elements/bdx_chasing_rock.txt
new file mode 100644 (file)
index 0000000..891d64e
--- /dev/null
@@ -0,0 +1,4 @@
+A chasing rock looks like an ordinary rock. It can even pass slime. It is
+lightweight, you can push it at once, as long as it is sleeping. Once it begins
+to fall, it wakes up and begins chasing you. You can also push awakened rocks,
+if you have eaten the sweet.
diff --git a/docs/elements/bdx_clock.txt b/docs/elements/bdx_clock.txt
new file mode 100644 (file)
index 0000000..bb74e36
--- /dev/null
@@ -0,0 +1 @@
+Collect this to get extra time.
diff --git a/docs/elements/bdx_conveyor.txt b/docs/elements/bdx_conveyor.txt
new file mode 100644 (file)
index 0000000..c378c0d
--- /dev/null
@@ -0,0 +1 @@
+Conveyor belts will move around any object that can fall.
diff --git a/docs/elements/bdx_conveyor_dir_switch.txt b/docs/elements/bdx_conveyor_dir_switch.txt
new file mode 100644 (file)
index 0000000..fb48f7e
--- /dev/null
@@ -0,0 +1 @@
+This switch can be used to reverse the direction of conveyor belts.
diff --git a/docs/elements/bdx_conveyor_switch.txt b/docs/elements/bdx_conveyor_switch.txt
new file mode 100644 (file)
index 0000000..f998078
--- /dev/null
@@ -0,0 +1 @@
+This switch turns the conveyor belts on or off.
diff --git a/docs/elements/bdx_covered.txt b/docs/elements/bdx_covered.txt
new file mode 100644 (file)
index 0000000..82ec6a1
--- /dev/null
@@ -0,0 +1 @@
+Covered tile.
diff --git a/docs/elements/bdx_cow.txt b/docs/elements/bdx_cow.txt
new file mode 100644 (file)
index 0000000..8abb4e5
--- /dev/null
@@ -0,0 +1,2 @@
+This creature wanders around the cave like a guard, but you can touch it.
+If it is enclosed, it turns into a skeleton.
diff --git a/docs/elements/bdx_creature_switch.txt b/docs/elements/bdx_creature_switch.txt
new file mode 100644 (file)
index 0000000..c731b1d
--- /dev/null
@@ -0,0 +1,2 @@
+With this switch you can change the direction of creatures, like guards and
+butterflies. Sometimes it works automatically.
diff --git a/docs/elements/bdx_diamond.txt b/docs/elements/bdx_diamond.txt
new file mode 100644 (file)
index 0000000..e176bf0
--- /dev/null
@@ -0,0 +1 @@
+A certain amount of these diamonds must be collected to solve a level.
diff --git a/docs/elements/bdx_diamond_glued.txt b/docs/elements/bdx_diamond_glued.txt
new file mode 100644 (file)
index 0000000..393c6b8
--- /dev/null
@@ -0,0 +1 @@
+Glued diamond.
diff --git a/docs/elements/bdx_diamond_key.txt b/docs/elements/bdx_diamond_key.txt
new file mode 100644 (file)
index 0000000..61180d6
--- /dev/null
@@ -0,0 +1 @@
+If you get this key, all doors will convert into diamonds you can collect.
diff --git a/docs/elements/bdx_dragonfly.txt b/docs/elements/bdx_dragonfly.txt
new file mode 100644 (file)
index 0000000..b76f2a0
--- /dev/null
@@ -0,0 +1,4 @@
+These creatures also guard the diamonds you would like to collect. But they
+move very differently. They like to run straight ahead, and only change
+direction if they bump into something. Like other enemies, you should not touch
+them. But you can easily crush them with rocks.
diff --git a/docs/elements/bdx_exit.txt b/docs/elements/bdx_exit.txt
new file mode 100644 (file)
index 0000000..7aa0482
--- /dev/null
@@ -0,0 +1,4 @@
+After collecting the required number of diamonds, look for a flashing out box
+to exit the cave. Closed out box looks like steel wall, but beware of explosions
+near the out box: You could accidentally destroy an exit. This prevents you from
+successfully finishing the cave.
diff --git a/docs/elements/bdx_expandable_steelwall.txt b/docs/elements/bdx_expandable_steelwall.txt
new file mode 100644 (file)
index 0000000..74c0406
--- /dev/null
@@ -0,0 +1 @@
+Expandable wall, but made of steel. You cannot even blow it up!
diff --git a/docs/elements/bdx_expandable_wall.txt b/docs/elements/bdx_expandable_wall.txt
new file mode 100644 (file)
index 0000000..16f0669
--- /dev/null
@@ -0,0 +1,3 @@
+Expandable wall expands in horizontal or vertical (or both) direction, if there
+is an empty space to fill up. You should be very careful not to be catched by
+the expanding wall.
diff --git a/docs/elements/bdx_expandable_wall_switch.txt b/docs/elements/bdx_expandable_wall_switch.txt
new file mode 100644 (file)
index 0000000..6de0c7a
--- /dev/null
@@ -0,0 +1 @@
+With this switch you can control the direction of the expandable wall.
diff --git a/docs/elements/bdx_expanding_wall_switch.txt b/docs/elements/bdx_expanding_wall_switch.txt
new file mode 100644 (file)
index 0000000..ec0c1dd
--- /dev/null
@@ -0,0 +1 @@
+Using this switch, you can control the direction of the expanding wall.
diff --git a/docs/elements/bdx_exploding.txt b/docs/elements/bdx_exploding.txt
new file mode 100644 (file)
index 0000000..71375a8
--- /dev/null
@@ -0,0 +1 @@
+BD style explosion.
diff --git a/docs/elements/bdx_fake_bonus.txt b/docs/elements/bdx_fake_bonus.txt
new file mode 100644 (file)
index 0000000..998a31f
--- /dev/null
@@ -0,0 +1 @@
+Fake bonus.
diff --git a/docs/elements/bdx_falling_wall.txt b/docs/elements/bdx_falling_wall.txt
new file mode 100644 (file)
index 0000000..193f727
--- /dev/null
@@ -0,0 +1,3 @@
+Whenever there is a falling wall above the player merely separated by empty
+space, it starts falling. It does so at any distance. If it hits the player,
+it explodes. If it hits anything else, it just stops.
diff --git a/docs/elements/bdx_firefly.txt b/docs/elements/bdx_firefly.txt
new file mode 100644 (file)
index 0000000..88411fc
--- /dev/null
@@ -0,0 +1,6 @@
+Fireflies move through empty space. Touching them is deadly.. Fireflies
+blow up when hit by a falling rock or diamond. Amoeba is also deadly for them.
+They explode into space, producing a 3x3 square of empty space. Fireflies are
+spinning left. They prefer turning left, usually counter-clockwise.
+
+There is another variant of the firefly that is spinning right.
diff --git a/docs/elements/bdx_flying_diamond.txt b/docs/elements/bdx_flying_diamond.txt
new file mode 100644 (file)
index 0000000..b2f1c95
--- /dev/null
@@ -0,0 +1,2 @@
+Exactly like a diamond, but instead of falling down, it flies upwards, as
+high as it can.
diff --git a/docs/elements/bdx_flying_rock.txt b/docs/elements/bdx_flying_rock.txt
new file mode 100644 (file)
index 0000000..a5b5139
--- /dev/null
@@ -0,0 +1,2 @@
+The flying variant of a rock. Note that this one can crush enemies as well as
+the player!
diff --git a/docs/elements/bdx_gate.txt b/docs/elements/bdx_gate.txt
new file mode 100644 (file)
index 0000000..2ccbb6a
--- /dev/null
@@ -0,0 +1 @@
+This is a door which can only be opened by the key of the same color.
diff --git a/docs/elements/bdx_ghost.txt b/docs/elements/bdx_ghost.txt
new file mode 100644 (file)
index 0000000..09215ae
--- /dev/null
@@ -0,0 +1,2 @@
+This is a ghost which wanders aimlessly. If it touches you, it will explode
+in an x-shape to many different elements.
diff --git a/docs/elements/bdx_gravestone.txt b/docs/elements/bdx_gravestone.txt
new file mode 100644 (file)
index 0000000..6403a72
--- /dev/null
@@ -0,0 +1 @@
+This is the gravestone for a dead voodoo doll.
diff --git a/docs/elements/bdx_gravity_switch.txt b/docs/elements/bdx_gravity_switch.txt
new file mode 100644 (file)
index 0000000..6e7d307
--- /dev/null
@@ -0,0 +1,3 @@
+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
+gravitation will change to.
diff --git a/docs/elements/bdx_inbox.txt b/docs/elements/bdx_inbox.txt
new file mode 100644 (file)
index 0000000..d03a012
--- /dev/null
@@ -0,0 +1 @@
+This is where the player enters a cave.
diff --git a/docs/elements/bdx_invisible_exit.txt b/docs/elements/bdx_invisible_exit.txt
new file mode 100644 (file)
index 0000000..b7c4e23
--- /dev/null
@@ -0,0 +1 @@
+This is also an exit, but it remains non-flashing and thus is difficult to find.
diff --git a/docs/elements/bdx_key.txt b/docs/elements/bdx_key.txt
new file mode 100644 (file)
index 0000000..99c9ad6
--- /dev/null
@@ -0,0 +1,2 @@
+There are three types of keys, which open three different colored doors.
+You can collect more from these; and for every door, always one key is used.
diff --git a/docs/elements/bdx_lava.txt b/docs/elements/bdx_lava.txt
new file mode 100644 (file)
index 0000000..e962217
--- /dev/null
@@ -0,0 +1,2 @@
+Heavy elements sink into the lava and disappear without any trace left.
+Creatures can also step into the lava.
diff --git a/docs/elements/bdx_magic_wall.txt b/docs/elements/bdx_magic_wall.txt
new file mode 100644 (file)
index 0000000..9cfca9c
--- /dev/null
@@ -0,0 +1,8 @@
+This magic wall converts rocks into diamonds and vice versa. Note that
+a magic wall can only be activated for some limited time. It can also turn mega
+rocks into nitro packs, nitro packs into mega rocks. Even flying diamonds and
+rocks pass them to be converted into each other, but they do that from bottom to
+up, of course.
+
+The duration in seconds for which magic walls are active is configurable.
+A duration of zero will let the wall run forever.
diff --git a/docs/elements/bdx_mega_rock.txt b/docs/elements/bdx_mega_rock.txt
new file mode 100644 (file)
index 0000000..3a45431
--- /dev/null
@@ -0,0 +1 @@
+Like an ordinary rock, but this one is so heavy that you cannot push it.
diff --git a/docs/elements/bdx_nitro_pack.txt b/docs/elements/bdx_nitro_pack.txt
new file mode 100644 (file)
index 0000000..eee0753
--- /dev/null
@@ -0,0 +1 @@
+Nitro pack.
diff --git a/docs/elements/bdx_nut.txt b/docs/elements/bdx_nut.txt
new file mode 100644 (file)
index 0000000..93fcd0d
--- /dev/null
@@ -0,0 +1 @@
+These nuts contain diamonds. If you crack them with a rock, they will be opened.
diff --git a/docs/elements/bdx_player.txt b/docs/elements/bdx_player.txt
new file mode 100644 (file)
index 0000000..2dccaf5
--- /dev/null
@@ -0,0 +1,2 @@
+This is the player. The player can move through empty space and sand, can pick
+up diamonds and push rocks, but should avoid fireflies and other enemies.
diff --git a/docs/elements/bdx_pneumatic_hammer.txt b/docs/elements/bdx_pneumatic_hammer.txt
new file mode 100644 (file)
index 0000000..6509a62
--- /dev/null
@@ -0,0 +1,5 @@
+Sometimes diamonds or keys are buried in walls. You can use a pneumatic hammer
+to break these walls, or simple walls which contain nothing. Stand on something,
+and press the snap or drop key together with a left or right direction key to
+use the hammer on a wall which is near the player, next to the element you
+stand on.
diff --git a/docs/elements/bdx_pot.txt b/docs/elements/bdx_pot.txt
new file mode 100644 (file)
index 0000000..a023971
--- /dev/null
@@ -0,0 +1,2 @@
+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.
diff --git a/docs/elements/bdx_replicator.txt b/docs/elements/bdx_replicator.txt
new file mode 100644 (file)
index 0000000..73b608e
--- /dev/null
@@ -0,0 +1,3 @@
+This machine replicates the element which is on top of it. At regular intervals,
+a new element drops out underneath, if there is space to do this. The rate of
+materializing the new elements can be different in every cave.
diff --git a/docs/elements/bdx_replicator_switch.txt b/docs/elements/bdx_replicator_switch.txt
new file mode 100644 (file)
index 0000000..894a5ff
--- /dev/null
@@ -0,0 +1 @@
+This turns the replicator on or off.
diff --git a/docs/elements/bdx_rock.txt b/docs/elements/bdx_rock.txt
new file mode 100644 (file)
index 0000000..d63a3be
--- /dev/null
@@ -0,0 +1,3 @@
+This is a rock (also called stone or boulder). It can be pushed by the
+player, and can be dropped on enemies to make them explode.
+This rock can be jump-pushed by snapping it.
diff --git a/docs/elements/bdx_rock_glued.txt b/docs/elements/bdx_rock_glued.txt
new file mode 100644 (file)
index 0000000..d308166
--- /dev/null
@@ -0,0 +1 @@
+Glued rock.
diff --git a/docs/elements/bdx_rocket.txt b/docs/elements/bdx_rocket.txt
new file mode 100644 (file)
index 0000000..d2bcca2
--- /dev/null
@@ -0,0 +1 @@
+A rocket that can be fired using the rocket launcher.
diff --git a/docs/elements/bdx_rocket_launcher.txt b/docs/elements/bdx_rocket_launcher.txt
new file mode 100644 (file)
index 0000000..92c4822
--- /dev/null
@@ -0,0 +1,3 @@
+If you find a rocket launcher, you can pick it up, and fire rockets.
+To use it, press fire and a direction key. Be careful not to make an
+explosion which is too close to the player.
diff --git a/docs/elements/bdx_sand.txt b/docs/elements/bdx_sand.txt
new file mode 100644 (file)
index 0000000..2b3f3d2
--- /dev/null
@@ -0,0 +1 @@
+You can move through sand, leaving empty space behind. Amoeba can eat it.
diff --git a/docs/elements/bdx_sand_ball.txt b/docs/elements/bdx_sand_ball.txt
new file mode 100644 (file)
index 0000000..4081eca
--- /dev/null
@@ -0,0 +1 @@
+A rolling ball of sand. You cannot push it, but you can dig it away.
diff --git a/docs/elements/bdx_sand_glued.txt b/docs/elements/bdx_sand_glued.txt
new file mode 100644 (file)
index 0000000..eafa168
--- /dev/null
@@ -0,0 +1 @@
+Glued sand.
diff --git a/docs/elements/bdx_sand_loose.txt b/docs/elements/bdx_sand_loose.txt
new file mode 100644 (file)
index 0000000..125daa0
--- /dev/null
@@ -0,0 +1 @@
+A falling piece of sand. You cannot push it, but you can dig it away.
diff --git a/docs/elements/bdx_sand_sloped.txt b/docs/elements/bdx_sand_sloped.txt
new file mode 100644 (file)
index 0000000..ade2961
--- /dev/null
@@ -0,0 +1,2 @@
+Acts like ordinary sand, but is sloped: Elements like rocks or diamonds
+will roll off to the left or right.
diff --git a/docs/elements/bdx_skeleton.txt b/docs/elements/bdx_skeleton.txt
new file mode 100644 (file)
index 0000000..d3e5824
--- /dev/null
@@ -0,0 +1,2 @@
+Sometimes you have to collect skeletons before you can use the pot. In some
+other caves, they must be collected like diamonds to open the exit.
diff --git a/docs/elements/bdx_slime.txt b/docs/elements/bdx_slime.txt
new file mode 100644 (file)
index 0000000..1876dcf
--- /dev/null
@@ -0,0 +1,2 @@
+Slime is permeable. It means that rocks and diamonds laying on the slime can
+randomly pass through.
diff --git a/docs/elements/bdx_steelwall.txt b/docs/elements/bdx_steelwall.txt
new file mode 100644 (file)
index 0000000..b7f7080
--- /dev/null
@@ -0,0 +1 @@
+This is rock stable wall. It's impossible to move or blow it up.
diff --git a/docs/elements/bdx_steelwall_diggable.txt b/docs/elements/bdx_steelwall_diggable.txt
new file mode 100644 (file)
index 0000000..4c5fbe5
--- /dev/null
@@ -0,0 +1 @@
+Acts like ordinary steel wall, but you can dig it away.
diff --git a/docs/elements/bdx_steelwall_explodable.txt b/docs/elements/bdx_steelwall_explodable.txt
new file mode 100644 (file)
index 0000000..2c85c61
--- /dev/null
@@ -0,0 +1 @@
+Acts like ordinary steel wall, but can be removed by explosions.
diff --git a/docs/elements/bdx_steelwall_sloped.txt b/docs/elements/bdx_steelwall_sloped.txt
new file mode 100644 (file)
index 0000000..be4a4c3
--- /dev/null
@@ -0,0 +1,2 @@
+Acts like ordinary steel wall, but is sloped: Elements like rocks or diamonds
+will roll off to the left or right.
diff --git a/docs/elements/bdx_stonefly.txt b/docs/elements/bdx_stonefly.txt
new file mode 100644 (file)
index 0000000..94dbc60
--- /dev/null
@@ -0,0 +1,2 @@
+This flying moth behaves just like a butterfly, except that it explodes into
+rocks instead of diamonds.
diff --git a/docs/elements/bdx_sweet.txt b/docs/elements/bdx_sweet.txt
new file mode 100644 (file)
index 0000000..534bf09
--- /dev/null
@@ -0,0 +1,2 @@
+Eat this sweet and you will become strong. You will be able to push rocks at
+once. You will also be able to push chasing rocks.
diff --git a/docs/elements/bdx_teleporter.txt b/docs/elements/bdx_teleporter.txt
new file mode 100644 (file)
index 0000000..c2408f9
--- /dev/null
@@ -0,0 +1,3 @@
+The teleporter will move you from one place to another, if you step into it.
+The destination teleporter depends on the direction from which you stepped into
+the teleporter.
diff --git a/docs/elements/bdx_time_penalty.txt b/docs/elements/bdx_time_penalty.txt
new file mode 100644 (file)
index 0000000..7aa6ece
--- /dev/null
@@ -0,0 +1 @@
+Time penalty.
diff --git a/docs/elements/bdx_trapped_diamond.txt b/docs/elements/bdx_trapped_diamond.txt
new file mode 100644 (file)
index 0000000..484c2cf
--- /dev/null
@@ -0,0 +1 @@
+This is an indestructible door with a diamond.
diff --git a/docs/elements/bdx_voodoo_doll.txt b/docs/elements/bdx_voodoo_doll.txt
new file mode 100644 (file)
index 0000000..313aba0
--- /dev/null
@@ -0,0 +1,6 @@
+This is your player's look-alike. You must protect it against flies. If a
+voodoo doll dies by one of them, your player also dies immediately. This doll
+can have different properties: Sometimes it can collect diamonds for you.
+Sometimes it must be protected from falling rocks. If it is hit by a rock, it
+turns into a gravestone surrounded by steel walls. Also, it may or may not turn
+into a gravestone by nearby explosions.
diff --git a/docs/elements/bdx_waiting_rock.txt b/docs/elements/bdx_waiting_rock.txt
new file mode 100644 (file)
index 0000000..9e992ba
--- /dev/null
@@ -0,0 +1 @@
+Waiting rock.
diff --git a/docs/elements/bdx_wall.txt b/docs/elements/bdx_wall.txt
new file mode 100644 (file)
index 0000000..b8bb46c
--- /dev/null
@@ -0,0 +1,5 @@
+This is a normal wall. It cannot be moved and cannot be passed by the player,
+but explosion will destroy it.
+
+Even though it may not look like that, objects that can fall will slip off this
+wall to the left or to the right.
diff --git a/docs/elements/bdx_wall_diamond.txt b/docs/elements/bdx_wall_diamond.txt
new file mode 100644 (file)
index 0000000..c8ca85d
--- /dev/null
@@ -0,0 +1 @@
+This wall contains a diamond which can be freed by using the pneumatic hammer.
diff --git a/docs/elements/bdx_wall_diggable.txt b/docs/elements/bdx_wall_diggable.txt
new file mode 100644 (file)
index 0000000..42b4de2
--- /dev/null
@@ -0,0 +1 @@
+Acts like ordinary wall, but you can dig it away.
diff --git a/docs/elements/bdx_wall_key.txt b/docs/elements/bdx_wall_key.txt
new file mode 100644 (file)
index 0000000..6d6eebb
--- /dev/null
@@ -0,0 +1,2 @@
+This is a key enclosed by a wall. Use the hammer to break this wall and get
+the key.
diff --git a/docs/elements/bdx_wall_sloped.txt b/docs/elements/bdx_wall_sloped.txt
new file mode 100644 (file)
index 0000000..34f7d46
--- /dev/null
@@ -0,0 +1,2 @@
+Acts like ordinary wall, but is sloped: Elements like rocks or diamonds
+will roll off to the left or right.
diff --git a/docs/elements/bdx_water.txt b/docs/elements/bdx_water.txt
new file mode 100644 (file)
index 0000000..f52781c
--- /dev/null
@@ -0,0 +1 @@
+Water, which floods all empty space slowly.
index 87fa244db19b6b287796514d6443850f1f977166..29a26e2ba3c945e3c3a06dc859e608d23d938d93 100644 (file)
@@ -1 +1 @@
-Crystals are indestructable and are worth a whopping 8 emeralds!
+Crystals are indestructible and are worth a whopping 8 emeralds!
index 084d69df23ea067700cdfdd48d8d81cfd081d886..eafe7d4a0334d5b21746c510bcb99c46762d7222 100644 (file)
@@ -1,8 +1,9 @@
-This is a (DC style) magic wall. It gets activated for a limited
-time by rocks or gems that fall on it. Objects falling though
-it will be changed to other objects. After it has stopped running,
-it cannot be activated again.
+This is a DC style magic wall. It gets activated for a limited duration by
+rocks or gems that fall on it. While activated, they can fall through it, and
+rocks turn into emeralds, emeralds turn into diamonds, diamonds turn into
+rocks, pearls turn into bombs, and crystals do not change.
+After the magic wall has stopped running, it cannot be activated again.
 
-The duration is expressed in seconds. A duration of zero will let the wall
-run forever. All regular magic walls run together; however, BD style magic
-walls have a separate counter.
+The duration in seconds for which magic walls are active is configurable.
+A duration of zero will let the wall run forever.
+All magic walls share the same timer.
diff --git a/docs/elements/df_mirror_fixed.txt b/docs/elements/df_mirror_fixed.txt
new file mode 100644 (file)
index 0000000..2d1c31a
--- /dev/null
@@ -0,0 +1 @@
+This fixed mirror reflects the laser beam into one direction only.
diff --git a/docs/elements/df_slope.txt b/docs/elements/df_slope.txt
new file mode 100644 (file)
index 0000000..ac49f18
--- /dev/null
@@ -0,0 +1 @@
+Steel slopes reflect the laser beam similar to steel walls.
index c17b45ded5570c1fd271bd28ecd06146808ca99d..3bd49118cf49a7445ca16846014cfb57f49aba4d 100644 (file)
@@ -1,8 +1,9 @@
-This is a (EM style) magic wall. It gets activated for a limited
-time by rocks or gems that fall on it. Objects falling though
-it will be changed to other objects. After it has stopped running,
-it cannot be activated again.
+This is an EM style magic wall. It gets activated for a limited duration by
+rocks or gems that fall on it. While activated, they can fall through it, and
+rocks turn into emeralds, emeralds turn into diamonds, and diamonds turn into
+rocks.
+After the magic wall has stopped running, it cannot be activated again.
 
-The duration is expressed in seconds. A duration of zero will let the wall
-run forever. All regular magic walls run together; however, BD style magic
-walls have a separate counter.
+The duration in seconds for which magic walls are active is configurable.
+A duration of zero will let the wall run forever.
+All magic walls share the same timer.
diff --git a/docs/elements/mm_envelope.txt b/docs/elements/mm_envelope.txt
new file mode 100644 (file)
index 0000000..041804f
--- /dev/null
@@ -0,0 +1,2 @@
+Envelopes can be configured to contain a text message for the player.
+All envelopes of the same color contain the same message.
index ef11ee09cac9896c6d0053888edd939f645f5f29..0f362b4b312741394dfa57484e5b6ce8fd7a3617 100644 (file)
@@ -1,2 +1,2 @@
-This magic exit door opens once all magic kettles have been collected.
+This magic exit door opens once all magic cauldrons have been collected.
 Redirect the magic ray of light into the exit door to finish the game.
index ee2ffa606a1fd8bf5d5e96073a71ef2c1c206a58..3f9b844ac0c4ff4e5d2094a62096bb046364ef17 100644 (file)
@@ -1,2 +1,2 @@
-Magic kettles contain ingredients for Gregor MacDuffin's magic spells and must
+Magic cauldrons contain ingredients for Gregor MacDuffin's magic spells and must
 all be collected before the magic exit door opens to finish the level.
index 8c248dabc50c36e797e81f6297f4d3fe845f3150..cb1cef29d07bdcfc16d30130d657271690b94190 100644 (file)
@@ -1,3 +1,3 @@
 This is our hero and magician Gregor McDuffin, who casts spells in the form
-of magic rays of light to collect all magic kettles (containing magic spell
+of magic rays of light to collect all magic cauldrons (containing magic spell
 ingredients).
index 4d40566d9d7e6f2f6f1ba8f3fdb4db8e051eaf87..b6bf1044b5b05a3f212a54a69203c26f6ab3dbdb 100644 (file)
@@ -1 +1 @@
-The pacmen move around, trying to eat all kettles and all amoeba walls.
+The pacmen move around, trying to eat all cauldrons and all amoeba walls.
index 889c573b43813c3bbc5054bdf0bb793d08a78f73..88ea268c1f3868969c8182dcd72f78896e54fbf3 100644 (file)
@@ -1 +1 @@
-This is a normal, destructable, slippery wall.
+This is a normal, destructible, slippery wall.
index 889c573b43813c3bbc5054bdf0bb793d08a78f73..88ea268c1f3868969c8182dcd72f78896e54fbf3 100644 (file)
@@ -1 +1 @@
-This is a normal, destructable, slippery wall.
+This is a normal, destructible, slippery wall.
index 889c573b43813c3bbc5054bdf0bb793d08a78f73..88ea268c1f3868969c8182dcd72f78896e54fbf3 100644 (file)
@@ -1 +1 @@
-This is a normal, destructable, slippery wall.
+This is a normal, destructible, slippery wall.
index 889c573b43813c3bbc5054bdf0bb793d08a78f73..88ea268c1f3868969c8182dcd72f78896e54fbf3 100644 (file)
@@ -1 +1 @@
-This is a normal, destructable, slippery wall.
+This is a normal, destructible, slippery wall.
index 889c573b43813c3bbc5054bdf0bb793d08a78f73..88ea268c1f3868969c8182dcd72f78896e54fbf3 100644 (file)
@@ -1 +1 @@
-This is a normal, destructable, slippery wall.
+This is a normal, destructible, slippery wall.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
index f8bd9311c4f68767b0b80a2dc70d5853a1d93d33..3ac72d26b5e9388c65c76e9a7b1d5af788140aa5 100644 (file)
@@ -1 +1 @@
-An indestructable, flat wall. Nothing's getting through this sucker.
+An indestructible, flat wall. Nothing's getting through this sucker.
diff --git a/docs/program/program_1.txt b/docs/program/program_1.txt
new file mode 100644 (file)
index 0000000..396a566
--- /dev/null
@@ -0,0 +1,22 @@
+# .font: font.text_2
+This game is Freeware!
+If you like it, send e-mail to:
+
+# .font: font.text_3
+info@artsoft.org
+
+
+
+# .font: font.text_2
+More information and levels:
+
+# .font: font.text_3
+https://www.artsoft.org/
+
+
+
+# .font: font.text_2
+If you have created new levels,
+send them to me to include them!
+
+:-)
diff --git a/graphics/gfx_classic/RocksBD.png b/graphics/gfx_classic/RocksBD.png
new file mode 100644 (file)
index 0000000..639080c
Binary files /dev/null and b/graphics/gfx_classic/RocksBD.png differ
diff --git a/graphics/gfx_classic/RocksBD2.png b/graphics/gfx_classic/RocksBD2.png
new file mode 100644 (file)
index 0000000..9d937f4
Binary files /dev/null and b/graphics/gfx_classic/RocksBD2.png differ
index 72bbb0a45da3616cdb90d1528d17e04838a46f21..5a5f1812253305a6b395ae5b1cf0eb3287c3be8e 100644 (file)
Binary files a/graphics/gfx_classic/RocksCE.png and b/graphics/gfx_classic/RocksCE.png differ
index e5a72bfb78b8459b50e3ff791028e0bcaf96ede6..710c556cb1085d441a54435118f702c2deb97e7a 100644 (file)
Binary files a/graphics/gfx_classic/RocksCollect.png and b/graphics/gfx_classic/RocksCollect.png differ
index dcc2e6efc206352570b5d48bc3fd752bc911ecbc..20fb45ee28fd79fca5403cec412773790b12e3cd 100644 (file)
Binary files a/graphics/gfx_classic/RocksDC.png and b/graphics/gfx_classic/RocksDC.png differ
index a33c2a487fa20312603d3f0322e76470ce6444a4..f20cafa633dac5228323b21ac865512869fc3b10 100644 (file)
Binary files a/graphics/gfx_classic/RocksDC2.png and b/graphics/gfx_classic/RocksDC2.png differ
index e8ea18d2e361a11f230763aaba413f532fd0a482..550512200fc93d48af93aafd8ba25b9f58a37f8c 100644 (file)
Binary files a/graphics/gfx_classic/RocksDF.png and b/graphics/gfx_classic/RocksDF.png differ
index 3d045d6fe69693769e377efe56e0e769d12ad3fc..c0feaa6c461544de04fc96711867d9742a00496c 100644 (file)
Binary files a/graphics/gfx_classic/RocksDoor.png and b/graphics/gfx_classic/RocksDoor.png differ
index 73efd72d531f0335a909cce09790a0d894ebf171..7d150be02f4870e85a87db166bd812208a54bd16 100644 (file)
Binary files a/graphics/gfx_classic/RocksDoor2.png and b/graphics/gfx_classic/RocksDoor2.png differ
index 6406fcb1e758905f2b8c6e79d7b5210e073b9a05..a765204f7cbe7184e630c6fb714505522e29c624 100644 (file)
Binary files a/graphics/gfx_classic/RocksEMC.png and b/graphics/gfx_classic/RocksEMC.png differ
index 8b0d40fb2d650b895693ad3675a57bdd6c47fe58..599809a6ae40712c9dc942e9a329d8a10474daa6 100644 (file)
Binary files a/graphics/gfx_classic/RocksElements.png and b/graphics/gfx_classic/RocksElements.png differ
diff --git a/graphics/gfx_classic/RocksIcon32x32.png b/graphics/gfx_classic/RocksIcon32x32.png
deleted file mode 100644 (file)
index dcd5112..0000000
Binary files a/graphics/gfx_classic/RocksIcon32x32.png and /dev/null differ
index b2b816ea85c78d96673edd089fc8b66d04944251..ac97f9527298465e21b98a078fc7a492a44ba068 100644 (file)
Binary files a/graphics/gfx_classic/RocksMM.png and b/graphics/gfx_classic/RocksMM.png differ
index 3ec708381c35d47baf8941be4cec544274ec215f..b9daca31613b00a0c07871e8f6297620a5463337 100644 (file)
Binary files a/graphics/gfx_classic/RocksSP.png and b/graphics/gfx_classic/RocksSP.png differ
index c42cacc44c9850134dccbb0737ea08fcbe794fc4..2a25840d9f3916bc99ce210c3ffc1b16f4bfedd1 100644 (file)
Binary files a/graphics/gfx_classic/RocksScreen.png and b/graphics/gfx_classic/RocksScreen.png differ
index 4cb63e9c68d4929844f6eab27cd17e4be683e0c0..919207ce5eaf21550ea24974081405c46842d1b5 100644 (file)
Binary files a/graphics/gfx_classic/RocksTouch.png and b/graphics/gfx_classic/RocksTouch.png differ
diff --git a/graphics/gfx_classic/icons/icon.png b/graphics/gfx_classic/icons/icon.png
new file mode 100644 (file)
index 0000000..8a4ae9c
Binary files /dev/null and b/graphics/gfx_classic/icons/icon.png differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/000.level b/levels/Tutorials/rnd_tutorial_ncrecc/000.level
new file mode 100644 (file)
index 0000000..64aff8d
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/000.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/001.level b/levels/Tutorials/rnd_tutorial_ncrecc/001.level
new file mode 100644 (file)
index 0000000..83e0383
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/001.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/002.level b/levels/Tutorials/rnd_tutorial_ncrecc/002.level
new file mode 100644 (file)
index 0000000..16e3a05
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/002.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/003.level b/levels/Tutorials/rnd_tutorial_ncrecc/003.level
new file mode 100644 (file)
index 0000000..f351dc5
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/003.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/004.level b/levels/Tutorials/rnd_tutorial_ncrecc/004.level
new file mode 100644 (file)
index 0000000..e71240e
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/004.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/005.level b/levels/Tutorials/rnd_tutorial_ncrecc/005.level
new file mode 100644 (file)
index 0000000..ae269cb
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/005.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/006.level b/levels/Tutorials/rnd_tutorial_ncrecc/006.level
new file mode 100644 (file)
index 0000000..e73c5f3
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/006.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/007.level b/levels/Tutorials/rnd_tutorial_ncrecc/007.level
new file mode 100644 (file)
index 0000000..4d69fdf
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/007.level differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/README.txt b/levels/Tutorials/rnd_tutorial_ncrecc/README.txt
new file mode 100644 (file)
index 0000000..2eb50c3
--- /dev/null
@@ -0,0 +1,18 @@
+a while ago i went... "man, some of these rnd elements could use tutorials!"
+specifically, things like emerald mine club and diamond caves 2 elements that
+aren't in the current built-in tutorials. so i sat down and made some catchy,
+fun tutorial levels for them.
+
+that "while ago" was 2018-2019. 3 years later, in 2022, i return to unearth this
+tutorial levelset. only 8 levels were finished despite plans for more, but it's
+better to have these available than not at all.
+
+the original version of this levelset included custom music from some modules
+i liked. this music has been removed in the interest of keeping it copyright
+friendly.
+
+i hope to update this in the future (or make a separare tutorial) to cover more
+advanced topics like player inventories, multiplayer, custom elements, and
+group elements.
+
+released in 2022 by ncrecc
\ No newline at end of file
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchBars.png b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchBars.png
new file mode 100644 (file)
index 0000000..af420bd
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchBars.png differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchPanel.png b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchPanel.png
new file mode 100644 (file)
index 0000000..2596ec5
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/RocksTooMuchPanel.png differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/graphics/graphicsinfo.conf b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/graphicsinfo.conf
new file mode 100644 (file)
index 0000000..8e8066a
--- /dev/null
@@ -0,0 +1,161 @@
+name:                           ncrtorial\r
+\r
+titlescreen_1:                  ncrtorial_title_screen.png\r
+titlescreen_1.scale_up_factor:  2\r
+background.PANEL:RocksTooMuchPanel.png\r
+background.PANEL.x:0\r
+background.PANEL.y:0\r
+background.PANEL.width:100\r
+background.PANEL.height:280\r
+game.panel.level_number.x:50\r
+game.panel.level_number.y:4\r
+game.panel.gems.y:31\r
+game.panel.inventory_count.y:58\r
+game.panel.inventory_last_1.x:5\r
+game.panel.inventory_last_1.y:57\r
+game.panel.inventory_last_1.draw_order:-2\r
+game.panel.inventory_last_1.tile_size:16\r
+game.panel.inventory_last_2.x:79\r
+game.panel.inventory_last_2.y:57\r
+game.panel.inventory_last_2.draw_order:-2\r
+game.panel.inventory_last_2.tile_size:16\r
+game.panel.graphic_1.x:3\r
+game.panel.graphic_1.y:64\r
+game.panel.graphic_1.draw_order:-1\r
+game.panel.graphic_1.draw_masked:true\r
+game.panel.graphic_2.x:77\r
+game.panel.graphic_2.y:64\r
+game.panel.graphic_2.draw_order:-1\r
+game.panel.graphic_2.draw_masked:true\r
+game.panel.element_1_count.x:25\r
+game.panel.element_1_count.y:85\r
+game.panel.element_1_count.align:left\r
+game.panel.element_1_count.digits:2\r
+game.panel.element_1_count.draw_order:-1\r
+game.panel.element_1_count.font:font.level_number\r
+game.panel.element_1_count.element:dynabomb_player_1.active\r
+game.panel.dynabomb_number.x:55\r
+game.panel.dynabomb_number.y:85\r
+game.panel.dynabomb_number.align:left\r
+game.panel.dynabomb_number.digits:2\r
+game.panel.dynabomb_number.draw_order:-1\r
+game.panel.dynabomb_number.font:font.level_number\r
+game.panel.dynabomb_size.x:50\r
+game.panel.dynabomb_size.y:103\r
+game.panel.dynabomb_size.align:center\r
+game.panel.dynabomb_size.draw_order:-1\r
+game.panel.dynabomb_size.digits:3\r
+game.panel.dynabomb_power.x:5\r
+game.panel.dynabomb_power.y:84\r
+game.panel.dynabomb_power.draw_order:-1\r
+game.panel.dynabomb_power.tile_size:16\r
+game.panel.time_anim.x:3\r
+game.panel.time_anim.y:46\r
+game.panel.health_anim.x:3\r
+game.panel.health_anim.y:82\r
+game.panel.key_1.x:3\r
+game.panel.key_1.y:129\r
+game.panel.key_1.draw_masked:true\r
+game.panel.key_2.x:18\r
+game.panel.key_2.y:129\r
+game.panel.key_2.draw_masked:true\r
+game.panel.key_3.x:33\r
+game.panel.key_3.y:129\r
+game.panel.key_3.draw_masked:true\r
+game.panel.key_4.x:48\r
+game.panel.key_4.y:129\r
+game.panel.key_4.draw_masked:true\r
+game.panel.key_5.x:64\r
+game.panel.key_5.y:129\r
+game.panel.key_5.draw_masked:true\r
+game.panel.key_6.x:80\r
+game.panel.key_6.y:129\r
+game.panel.key_6.draw_masked:true\r
+game.panel.key_7.x:4\r
+game.panel.key_7.y:142\r
+game.panel.key_7.draw_masked:true\r
+game.panel.key_8.x:20\r
+game.panel.key_8.y:142\r
+game.panel.key_8.draw_masked:true\r
+game.panel.key_white.x:80\r
+game.panel.key_white.y:142\r
+game.panel.key_white.draw_masked:true\r
+game.panel.key_white_count.x:79\r
+game.panel.key_white_count.y:143\r
+game.panel.key_white_count.align:right\r
+game.panel.key_white_count.digits:-1\r
+game.panel.key_white_count.font:font.level_number\r
+game.panel.score.y:170\r
+game.panel.time.y:197\r
+dynabomb_increase_power.PANEL:RocksTooMuchPanel.png\r
+dynabomb_increase_power.PANEL.xoffset:6\r
+dynabomb_increase_power.PANEL.yoffset:216\r
+dynabomb_increase_power.PANEL.frames:2\r
+dynabomb_increase_power.PANEL.anim_mode:linear\r
+dynabomb_increase_power.PANEL.start_frame:1\r
+#dynabomb_player_1.PANEL:RocksTooMuchPanel.png\r
+#dynabomb_player_1.PANEL.xoffset:38\r
+#dynabomb_player_1.PANEL.yoffset:216\r
+#dynabomb_player_1.PANEL.frames:2\r
+#dynabomb_player_1.PANEL.anim_mode:linear\r
+#dynabomb_player_1.PANEL.start_frame:1\r
+emc_key_5.PANEL:RocksTooMuchPanel.png\r
+emc_key_5.PANEL.xoffset:38\r
+emc_key_5.PANEL.yoffset:216\r
+emc_key_5.PANEL.frames:2\r
+emc_key_5.PANEL.anim_mode:linear\r
+emc_key_5.PANEL.start_frame:1\r
+emc_key_6.PANEL:RocksTooMuchPanel.png\r
+emc_key_6.PANEL.xoffset:38\r
+emc_key_6.PANEL.yoffset:242\r
+emc_key_6.PANEL.frames:2\r
+emc_key_6.PANEL.anim_mode:linear\r
+emc_key_6.PANEL.start_frame:1\r
+emc_key_7.PANEL:RocksTooMuchPanel.png\r
+emc_key_7.PANEL.xpos:0\r
+emc_key_7.PANEL.ypos:9\r
+emc_key_7.PANEL.frames:1\r
+emc_key_8.PANEL:RocksTooMuchPanel.png\r
+emc_key_8.PANEL.xpos:1\r
+emc_key_8.PANEL.ypos:9\r
+emc_key_8.PANEL.frames:1\r
+dc_key_white.PANEL:RocksTooMuchPanel.png\r
+dc_key_white.PANEL.xpos:2\r
+dc_key_white.PANEL.ypos:9\r
+dc_key_white.PANEL.frames:1\r
+graphic_1:RocksTooMuchPanel.png\r
+graphic_1.x:5\r
+graphic_1.y:265\r
+graphic_1.width:8\r
+graphic_1.height:10\r
+graphic_1.frames:1\r
+graphic_2:RocksTooMuchPanel.png\r
+graphic_2.x:13\r
+graphic_2.y:265\r
+graphic_2.width:8\r
+graphic_2.height:10\r
+graphic_2.frames:1\r
+gfx.game.panel.time_anim:RocksTooMuchBars.png\r
+gfx.game.panel.time_anim.x:0\r
+gfx.game.panel.time_anim.y:0\r
+gfx.game.panel.time_anim.width:94\r
+gfx.game.panel.time_anim.height:36\r
+gfx.game.panel.time_anim.frames:1\r
+gfx.game.panel.time_anim.active:RocksTooMuchBars.png\r
+gfx.game.panel.time_anim.active.x:94\r
+gfx.game.panel.time_anim.active.y:0\r
+gfx.game.panel.time_anim.active.width:94\r
+gfx.game.panel.time_anim.active.height:36\r
+gfx.game.panel.time_anim.active.frames:1\r
+gfx.game.panel.health_anim:RocksTooMuchBars.png\r
+gfx.game.panel.health_anim.x:0\r
+gfx.game.panel.health_anim.y:36\r
+gfx.game.panel.health_anim.width:94\r
+gfx.game.panel.health_anim.height:38\r
+gfx.game.panel.health_anim.frames:1\r
+gfx.game.panel.health_anim.active:RocksTooMuchBars.png\r
+gfx.game.panel.health_anim.active.x:94\r
+gfx.game.panel.health_anim.active.y:36\r
+gfx.game.panel.health_anim.active.width:94\r
+gfx.game.panel.health_anim.active.height:38\r
+gfx.game.panel.health_anim.active.frames:1
\ No newline at end of file
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/graphics/ncrtorial_title_screen.png b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/ncrtorial_title_screen.png
new file mode 100644 (file)
index 0000000..5da222c
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/graphics/ncrtorial_title_screen.png differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/levelinfo.conf b/levels/Tutorials/rnd_tutorial_ncrecc/levelinfo.conf
new file mode 100644 (file)
index 0000000..c02b8e0
--- /dev/null
@@ -0,0 +1,11 @@
+# =============================================================================
+# levelinfo.conf
+# =============================================================================
+
+name:                           Ncrecc's Tutorial - ncrtorial
+author:                         ncrecc
+
+levels:                         8
+first_level:                    0
+
+sort_priority:                  20
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape
new file mode 100644 (file)
index 0000000..a75f9c2
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape.BROKEN b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape.BROKEN
new file mode 100644 (file)
index 0000000..010a768
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000.tape.BROKEN differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000_TAS.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000_TAS.tape
new file mode 100644 (file)
index 0000000..94d496c
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/000_TAS.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/001.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/001.tape
new file mode 100644 (file)
index 0000000..0a8e3ff
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/001.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/002.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/002.tape
new file mode 100644 (file)
index 0000000..1165b7d
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/002.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/003.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/003.tape
new file mode 100644 (file)
index 0000000..d9dc3fd
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/003.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/004.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/004.tape
new file mode 100644 (file)
index 0000000..fc2c0ec
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/004.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/005.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/005.tape
new file mode 100644 (file)
index 0000000..72a32e8
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/005.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/006.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/006.tape
new file mode 100644 (file)
index 0000000..8739b96
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/006.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/tapes/007.tape b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/007.tape
new file mode 100644 (file)
index 0000000..6cca184
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/tapes/007.tape differ
diff --git a/levels/Tutorials/rnd_tutorial_ncrecc/unused.level b/levels/Tutorials/rnd_tutorial_ncrecc/unused.level
new file mode 100644 (file)
index 0000000..be21c47
Binary files /dev/null and b/levels/Tutorials/rnd_tutorial_ncrecc/unused.level differ
index 7cd4daa8bdf0fb377942e1f98737d592b8860902..7b4fdc92b2f2d53b9587a33f009742c9004fbca1 100644 (file)
@@ -1,26 +1,30 @@
+# .font: font.text_2
 NB's Introduction Levels
-~~~~~~~~~~~~~~~~~~~~~~~~
 
+# .font: font.text_1
 About
-------
+
+# .font: font.info.levelset
 These levels are meant as an advanced tutorial, where (nearly) all of the
 Rocks'n'Diamonds elements are introduced (with one exception; see below).
 
 Each level contains either one or more associated new elements. Mostly there
 is also an envelope explaining the new elements.
 
-The only elements not present are gravitiy ports. Because gravity is
+The only elements not present are gravity ports. Because gravity is
 introduced not until the last level and they originally belong to Supaplex,
 they simply didn't fit in anywhere ;)
 
-
+# .font: font.text_1
 Legal notes
-------------
+
+# .font: font.info.levelset
 You may do anything with these levels as long as they or any derived work
 of them are made available freely. If you however want to charge money for
 derived work, please contact the author first.
 
+# .font: font.text_1
+Contact
 
-Contact:
----------
-Niko Böhm <flummi@semisane.de>
+# .font: font.info.levelset
+Niko Böhm <flummi@semisane.de>
diff --git a/levels/Tutorials/rnd_tutorial_niko_boehm/README.orig b/levels/Tutorials/rnd_tutorial_niko_boehm/README.orig
new file mode 100644 (file)
index 0000000..7cd4daa
--- /dev/null
@@ -0,0 +1,26 @@
+NB's Introduction Levels
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+About
+------
+These levels are meant as an advanced tutorial, where (nearly) all of the
+Rocks'n'Diamonds elements are introduced (with one exception; see below).
+
+Each level contains either one or more associated new elements. Mostly there
+is also an envelope explaining the new elements.
+
+The only elements not present are gravitiy ports. Because gravity is
+introduced not until the last level and they originally belong to Supaplex,
+they simply didn't fit in anywhere ;)
+
+
+Legal notes
+------------
+You may do anything with these levels as long as they or any derived work
+of them are made available freely. If you however want to charge money for
+derived work, please contact the author first.
+
+
+Contact:
+---------
+Niko Böhm <flummi@semisane.de>
diff --git a/levels/Tutorials/rnd_tutorial_niko_boehm/README.txt b/levels/Tutorials/rnd_tutorial_niko_boehm/README.txt
new file mode 100644 (file)
index 0000000..56ee097
--- /dev/null
@@ -0,0 +1,23 @@
+NB's Introduction Levels
+
+About  
+-----  
+These levels are meant as an advanced tutorial, where (nearly) all of the
+Rocks'n'Diamonds elements are introduced (with one exception; see below).
+
+Each level contains either one or more associated new elements. Mostly there
+is also an envelope explaining the new elements.
+
+The only elements not present are gravity ports. Because gravity is
+introduced not until the last level and they originally belong to Supaplex,
+they simply didn't fit in anywhere ;)
+
+Legal notes  
+-----------  
+You may do anything with these levels as long as they or any derived work
+of them are made available freely. If you however want to charge money for
+derived work, please contact the author first.
+
+Contact  
+-------  
+Niko Böhm <flummi@semisane.de>
index d9ebce2c121a989878282dc12fc73e8d81fe6dae..32217cc2806401671ec66d172ebec652fac17efe 100644 (file)
Binary files a/music/mus_classic/rhythmloop.wav and b/music/mus_classic/rhythmloop.wav differ
index e691946f64acf1344ba34494db9de0139b3f60dc..0e041dae9dc85759b8262dc9c37bc4a721f990df 100644 (file)
Binary files a/sounds/snd_classic/autsch.wav and b/sounds/snd_classic/autsch.wav differ
index 9808fc1ae0e6231a7c526616bdc703e09819983a..d917ae87f2eb4dd5ca38f08954285b06a7aaed6c 100644 (file)
Binary files a/sounds/snd_classic/bong.wav and b/sounds/snd_classic/bong.wav differ
diff --git a/sounds/snd_classic/crash.wav b/sounds/snd_classic/crash.wav
new file mode 100644 (file)
index 0000000..a193e9f
Binary files /dev/null and b/sounds/snd_classic/crash.wav differ
index cc9463c9d8b97d93645bf38adf33ee8214035fd9..667e9b20bc7bf0dd097dd8943798d12985922f61 100644 (file)
Binary files a/sounds/snd_classic/fuel.wav and b/sounds/snd_classic/fuel.wav differ
index a09ea5c0ddaf3850aba802cd45fdb0c80edc85b3..7e9f84bfd291e0f70c6be1ef0c0e6c955bac18d6 100644 (file)
Binary files a/sounds/snd_classic/halloffame.wav and b/sounds/snd_classic/halloffame.wav differ
diff --git a/sounds/snd_classic/hammer.wav b/sounds/snd_classic/hammer.wav
new file mode 100644 (file)
index 0000000..2d79607
Binary files /dev/null and b/sounds/snd_classic/hammer.wav differ
diff --git a/sounds/snd_classic/jingle.wav b/sounds/snd_classic/jingle.wav
new file mode 100644 (file)
index 0000000..a009f80
Binary files /dev/null and b/sounds/snd_classic/jingle.wav differ
index 517415021a13943cb6d0ee03307198e031dcae50..f076793a42f80251f41ace9db19f92951220f35c 100644 (file)
@@ -1,7 +1,7 @@
 # =============================================================================
 # 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/
@@ -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/list.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           \
+       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              \
@@ -105,6 +119,7 @@ LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.c \
        files.c                         \
        tape.c                          \
        anim.c                          \
+       api.c                           \
        network.c                       \
        netserv.c
 
index 0456b906a58798e4a7c5728b791ce757abe66e54..7a128e75ed18b79b4e3f97cf34ff6abafe2d0479 100644 (file)
@@ -44,8 +44,6 @@ DEBUGGER = gdb -batch -ex "run" -ex "bt"
 PROGBASE = rocksndiamonds
 PROGNAME = ../$(PROGBASE)
 
-EDITION ?= default
-
 
 # -----------------------------------------------------------------------------
 # configuring platform
@@ -62,14 +60,17 @@ endif
 
 ifeq ($(PLATFORM),emscripten)          # compiling with Emscripten
 PROGNAME = ../$(PROGBASE).js
+DATA_FILE = $(PROGBASE).data
 CC = emcc
 AR = emar
 RANLIB = emranlib
 STRIP = true
+FILE_PACKAGER = file_packager
 endif
 
 ifeq ($(shell uname -s),Darwin)                # compiling on Mac OS X
 DEBUGGER = lldb --batch -o "run" -k "bt" -k "quit"
+SANITIZING_FLAGS = -fsanitize=undefined
 ifdef BUILD_DIST                       # distribution build
 MAC_TARGET_VERSION_MIN = 10.7
 EXTRA_FLAGS_MAC = -mmacosx-version-min=$(MAC_TARGET_VERSION_MIN)
@@ -79,6 +80,11 @@ MACOSX_DEPLOYMENT_TARGET = $MAC_TARGET_VERSION_MIN
 endif
 endif
 
+ifeq ($(shell uname -s),OS/2)          # compiling on OS/2
+PROGNAME = ../$(PROGBASE).exe
+EXTRA_LDFLAGS = -Zomf -Zbin-files -Zmap -lcx -Zhigh-mem
+endif
+
 
 # -----------------------------------------------------------------------------
 # configuring target
@@ -97,10 +103,12 @@ endif
 
 ifeq ($(TARGET),sdl2)                  # compiling for SDL2 target
 ifeq ($(PLATFORM),emscripten)
-SDL_LIBS = -s USE_SDL_IMAGE=2 -s USE_SDL_MIXER=2 -s USE_SDL_NET=2 -s USE_ZLIB=1
-SDL_FMTS = -s SDL2_IMAGE_FORMATS='["bmp","png","pcx","xpm"]'
+SDL_LIBS = -s USE_SDL_IMAGE=2 -s USE_SDL_MIXER=2 -s USE_SDL_NET=2 -s USE_MODPLUG=1 -s USE_MPG123=1 -s USE_ZLIB=1
+SDL_FMTS = -s SDL2_IMAGE_FORMATS='["bmp","png","pcx","xpm"]' -s SDL2_MIXER_FORMATS='["mod","mp3"]'
 EXTRA_CFLAGS = $(SDL_LIBS)
-EXTRA_LDFLAGS = $(SDL_FMTS) -s INITIAL_MEMORY=81920000 -s ALLOW_MEMORY_GROWTH=1 --preload-file ../conf/ --preload-file ../docs/ --preload-file ../levels/ --preload-file ../graphics/ --preload-file ../sounds/ --preload-file ../music/ -s NO_EXIT_RUNTIME=0 -s ASYNCIFY -O2 -lidbfs.js
+EXTRA_LDFLAGS = $(SDL_FMTS) -s INITIAL_MEMORY=81920000 -s ALLOW_MEMORY_GROWTH=1 -s FORCE_FILESYSTEM -s NO_EXIT_RUNTIME=0 -s ASYNCIFY -O2 -lidbfs.js
+DATA_DIRS = conf docs levels graphics sounds music
+FILE_PACKAGER_ARGS = --preload $(DATA_DIRS) --js-output=$(DATA_FILE).js
 else
 SDL_LIBS = -lSDL2_image -lSDL2_mixer -lSDL2_net
 endif
@@ -122,12 +130,14 @@ CONFIG = $(CONFIG_BASE_PATH) $(JOYSTICK)
 
 DEBUG = -DDEBUG -g
 
-# PROFILING = $(PROFILING_FLAGS)
+# ANALYZE = $(PROFILING_FLAGS)
+# ANALYZE = $(SANITIZING_FLAGS)
 
 # OPTIONS = $(DEBUG) -Wall                     # only for debugging purposes
 # OPTIONS = $(DEBUG) -O2 -Wall                 # only for debugging purposes
 # OPTIONS = $(DEBUG) -Wall                     # only for debugging purposes
 OPTIONS = $(DEBUG) -Wall -Wstrict-prototypes -Wmissing-prototypes
+# OPTIONS = $(DEBUG) -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes
 # OPTIONS = $(DEBUG) -Wall -ansi -pedantic     # only for debugging purposes
 # OPTIONS = -O2 -Wall -ansi -pedantic
 # OPTIONS = -O2 -Wall
@@ -143,8 +153,8 @@ SYS_LDFLAGS := $(shell echo $(SYS_LDFLAGS) |        \
 OPTIONS = -O2 -Wall
 endif
 
-CFLAGS = $(OPTIONS) $(SYS_CFLAGS)  $(EXTRA_CFLAGS) $(CONFIG)
-LDFLAGS =           $(SYS_LDFLAGS) $(EXTRA_LDFLAGS)
+CFLAGS = $(OPTIONS) $(ANALYZE) $(SYS_CFLAGS)  $(EXTRA_CFLAGS) $(CONFIG)
+LDFLAGS =           $(ANALYZE) $(SYS_LDFLAGS) $(EXTRA_LDFLAGS)
 
 
 SRCS = main.c          \
@@ -162,6 +172,7 @@ SRCS =      main.c          \
        files.c         \
        tape.c          \
        anim.c          \
+       api.c           \
        network.c       \
        netserv.c
 
@@ -180,6 +191,7 @@ OBJS =      main.o          \
        files.o         \
        tape.o          \
        anim.o          \
+       api.o           \
        network.o       \
        netserv.o
 
@@ -192,6 +204,8 @@ CNFS =      conf_gfx.h      \
        conf_cus.h      \
        conf_grp.c      \
        conf_grp.h      \
+       conf_emp.c      \
+       conf_emp.h      \
        conf_e2g.c      \
        conf_esg.c      \
        conf_e2s.c      \
@@ -221,6 +235,9 @@ SOURCE_HASH_STRING ?= $(shell test -d ../.git && test `git ls-files -m | wc -l`
 LIBGAME_DIR = libgame
 LIBGAME = $(LIBGAME_DIR)/libgame.a
 
+GAME_BD_DIR = game_bd
+GAME_BD = $(GAME_BD_DIR)/game_bd.a
+
 GAME_EM_DIR = game_em
 GAME_EM = $(GAME_EM_DIR)/game_em.a
 
@@ -230,14 +247,14 @@ GAME_SP = $(GAME_SP_DIR)/game_sp.a
 GAME_MM_DIR = game_mm
 GAME_MM = $(GAME_MM_DIR)/game_mm.a
 
-RNDLIBS = $(LIBGAME) $(GAME_EM) $(GAME_SP) $(GAME_MM)
+RNDLIBS = $(GAME_BD) $(GAME_EM) $(GAME_SP) $(GAME_MM) $(LIBGAME)
 AUTOCONF = conf_gfx.h conf_snd.h conf_mus.h
 
 ICONBASE = windows_icon
-ICON_BASEPATH = ../Special/Icons/windows_icons
+ICON_BASEPATH = ../build-projects/windows/icons
 
 ifeq ($(PLATFORM_BASE),cross-win)
-ICON_PATH = $(ICON_BASEPATH)/$(EDITION)
+ICON_PATH = $(ICON_BASEPATH)
 ICON = $(ICONBASE).o
 endif
 
@@ -248,19 +265,27 @@ GRAPHICS_DIR = ../graphics
 # build targets
 # -----------------------------------------------------------------------------
 
-all: $(AUTOCONF) libgame_dir game_em_dir game_sp_dir game_mm_dir $(PROGNAME) graphics_dir
+all: $(AUTOCONF) libgame_dir game_bd_dir game_em_dir game_sp_dir game_mm_dir $(PROGNAME) graphics_dir
 
 $(PROGNAME): $(RNDLIBS) $(TIMESTAMP_FILE) $(COMMIT_HASH_FILE) $(OBJS) $(ICON)
-       $(CC) $(PROFILING) $(OBJS) $(ICON) $(RNDLIBS) $(LDFLAGS) -o $(PROGNAME)
+       $(CC) $(OBJS) $(ICON) $(RNDLIBS) $(LDFLAGS) -o $(PROGNAME)
 ifdef BUILD_DIST
        $(STRIP) $(PROGNAME)
 endif
+ifeq ($(PLATFORM),emscripten)
+       (cd .. ; $(FILE_PACKAGER) $(DATA_FILE) $(FILE_PACKAGER_ARGS))
+endif
 
 libgame_dir:
        @$(MAKE) -C $(LIBGAME_DIR)
 $(LIBGAME):
        @$(MAKE) -C $(LIBGAME_DIR)
 
+game_bd_dir:
+       @$(MAKE) -C $(GAME_BD_DIR)
+$(GAME_BD):
+       @$(MAKE) -C $(GAME_BD_DIR)
+
 game_em_dir:
        @$(MAKE) -C $(GAME_EM_DIR)
 $(GAME_EM):
@@ -305,6 +330,8 @@ conf-hash:
        @echo '#define SOURCE_HASH_STRING "$(SOURCE_HASH_STRING)"' \
        > $(COMMIT_HASH_FILE)
 
+config.o: config.c $(TIMESTAMP_FILE)
+
 $(TIMESTAMP_FILE): $(SRCS) $(RNDLIBS)
        @$(MAKE) conf-time
 
@@ -312,18 +339,18 @@ $(COMMIT_HASH_FILE): $(SRCS) $(RNDLIBS)
        @$(MAKE) conf-hash
 
 $(ICON):
-#      $(CONVERT) $(ICON32X32) $(CONVERT_ICON_ARGS) $(ICONBASE).ico
        $(CONVERT) $(ICON_PATH)/*.png $(CONVERT_ICON_ARGS) $(ICONBASE).ico
        echo "$(ICONBASE) ICON $(ICONBASE).ico" | $(WINDRES) -o $(ICON)
 
 .c.o:
-       $(CC) $(PROFILING) $(CFLAGS) -c $*.c
+       $(CC) $(CFLAGS) -c $*.c
 
 graphics_dir:
        @test -f $(GRAPHICS_DIR)/Makefile && $(MAKE) -C $(GRAPHICS_DIR) || true
 
 clean-obj:
        $(MAKE) -C $(LIBGAME_DIR) clean
+       $(MAKE) -C $(GAME_BD_DIR) clean
        $(MAKE) -C $(GAME_EM_DIR) clean
        $(MAKE) -C $(GAME_SP_DIR) clean
        $(MAKE) -C $(GAME_MM_DIR) clean
@@ -368,15 +395,24 @@ valgrind:
 # -----------------------------------------------------------------------------
 
 tags:
-       $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch] $(GAME_SP_DIR)/*.[ch] $(GAME_MM_DIR)/*.[ch]
+       $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_BD_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch] $(GAME_SP_DIR)/*.[ch] $(GAME_MM_DIR)/*.[ch]
 
 depend:
        $(MAKE) -C $(LIBGAME_DIR) depend
+       $(MAKE) -C $(GAME_BD_DIR) depend
        $(MAKE) -C $(GAME_EM_DIR) depend
        $(MAKE) -C $(GAME_SP_DIR) depend
        $(MAKE) -C $(GAME_MM_DIR) depend
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
+depend-clean:
+       $(MAKE) -C $(LIBGAME_DIR) depend-clean
+       $(MAKE) -C $(GAME_BD_DIR) depend-clean
+       $(MAKE) -C $(GAME_EM_DIR) depend-clean
+       $(MAKE) -C $(GAME_SP_DIR) depend-clean
+       $(MAKE) -C $(GAME_MM_DIR) depend-clean
+       $(RM) .depend
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
index c2ec75f64c65a87ea17212d0a66c34773de1a0d4..53435a97a71f660a6c5c62c904220ed3890f0fa3 100644 (file)
@@ -17,6 +17,7 @@
 #include "files.h"
 #include "events.h"
 #include "screens.h"
+#include "tape.h"
 
 
 #define DEBUG_ANIM_DELAY               0
 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS        MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
                                            NUM_GLOBAL_TOON_PARTS)
 
+#define MAX_GLOBAL_ANIM_LIST           (NUM_GAME_MODES *               \
+                                        NUM_GLOBAL_ANIMS_AND_TOONS *   \
+                                        NUM_GLOBAL_ANIM_PARTS_AND_TOONS)
+
 #define ANIM_CLASS_BIT_TITLE_INITIAL   0
 #define ANIM_CLASS_BIT_TITLE           1
 #define ANIM_CLASS_BIT_MAIN            2
-#define ANIM_CLASS_BIT_SCORES          3
-#define ANIM_CLASS_BIT_SUBMENU         4
-#define ANIM_CLASS_BIT_MENU            5
-#define ANIM_CLASS_BIT_TOONS           6
-#define ANIM_CLASS_BIT_NO_TITLE                7
+#define ANIM_CLASS_BIT_NAMES           3
+#define ANIM_CLASS_BIT_SCORES          4
+#define ANIM_CLASS_BIT_SCORESONLY      5
+#define ANIM_CLASS_BIT_SUBMENU         6
+#define ANIM_CLASS_BIT_MENU            7
+#define ANIM_CLASS_BIT_TOONS           8
+#define ANIM_CLASS_BIT_NO_TITLE                9
 
-#define NUM_ANIM_CLASSES               8
+#define NUM_ANIM_CLASSES               10
 
 #define ANIM_CLASS_NONE                        0
 #define ANIM_CLASS_TITLE_INITIAL       (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
 #define ANIM_CLASS_TITLE               (1 << ANIM_CLASS_BIT_TITLE)
 #define ANIM_CLASS_MAIN                        (1 << ANIM_CLASS_BIT_MAIN)
+#define ANIM_CLASS_NAMES               (1 << ANIM_CLASS_BIT_NAMES)
 #define ANIM_CLASS_SCORES              (1 << ANIM_CLASS_BIT_SCORES)
+#define ANIM_CLASS_SCORESONLY          (1 << ANIM_CLASS_BIT_SCORESONLY)
 #define ANIM_CLASS_SUBMENU             (1 << ANIM_CLASS_BIT_SUBMENU)
 #define ANIM_CLASS_MENU                        (1 << ANIM_CLASS_BIT_MENU)
 #define ANIM_CLASS_TOONS               (1 << ANIM_CLASS_BIT_TOONS)
                                         ANIM_CLASS_SCORES      |       \
                                         ANIM_CLASS_NO_TITLE)
 
+#define ANIM_CLASS_TOONS_SCORESONLY    (ANIM_CLASS_TOONS       |       \
+                                        ANIM_CLASS_SCORES      |       \
+                                        ANIM_CLASS_SCORESONLY  |       \
+                                        ANIM_CLASS_NO_TITLE)
+
 #define ANIM_CLASS_TOONS_MENU_MAIN     (ANIM_CLASS_TOONS       |       \
                                         ANIM_CLASS_MENU        |       \
                                         ANIM_CLASS_MAIN        |       \
                                         ANIM_CLASS_SUBMENU     |       \
                                         ANIM_CLASS_NO_TITLE)
 
+#define ANIM_CLASS_TOONS_MENU_SUBMENU_2        (ANIM_CLASS_TOONS       |       \
+                                        ANIM_CLASS_MENU        |       \
+                                        ANIM_CLASS_SUBMENU     |       \
+                                        ANIM_CLASS_NAMES       |       \
+                                        ANIM_CLASS_NO_TITLE)
+
 // values for global animation states
 #define ANIM_STATE_INACTIVE            0
 #define ANIM_STATE_RESTART             (1 << 0)
@@ -99,6 +119,8 @@ struct GlobalAnimPartControlInfo
   struct GraphicInfo graphic_info;
   struct GraphicInfo control_info;
 
+  boolean class_playfield_or_door;
+
   int viewport_x;
   int viewport_y;
   int viewport_width;
@@ -107,14 +129,21 @@ struct GlobalAnimPartControlInfo
   int x, y;
   int step_xoffset, step_yoffset;
 
+  int tile_x, tile_y;
+  int tile_xoffset, tile_yoffset;
+
   unsigned int initial_anim_sync_frame;
   unsigned int anim_random_frame;
-  unsigned int step_delay, step_delay_value;
+
+  DelayCounter step_delay;
 
   int init_delay_counter;
   int anim_delay_counter;
   int post_delay_counter;
 
+  int fade_delay_counter;
+  int fade_alpha;
+
   boolean init_event_state;
   boolean anim_event_state;
 
@@ -183,12 +212,13 @@ struct GameModeAnimClass
   { GAME_MODE_LEVELNR,                 ANIM_CLASS_TOONS_MENU_SUBMENU   },
   { GAME_MODE_INFO,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
   { GAME_MODE_SETUP,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
-  { GAME_MODE_PSEUDO_NAMESONLY,                ANIM_CLASS_TOONS_MENU_SUBMENU   },
-  { GAME_MODE_PSEUDO_TYPENAMES,                ANIM_CLASS_TOONS_MENU_SUBMENU   },
+  { GAME_MODE_PSEUDO_NAMESONLY,                ANIM_CLASS_TOONS_MENU_SUBMENU_2 },
+  { GAME_MODE_PSEUDO_TYPENAMES,                ANIM_CLASS_TOONS_MENU_SUBMENU_2 },
   { GAME_MODE_PSEUDO_MAINONLY,         ANIM_CLASS_TOONS_MENU_MAIN      },
   { GAME_MODE_PSEUDO_TYPENAME,         ANIM_CLASS_TOONS_MENU_MAIN      },
-  { GAME_MODE_PSEUDO_SCORESOLD,                ANIM_CLASS_TOONS_SCORES         },
-  { GAME_MODE_PSEUDO_SCORESNEW,                ANIM_CLASS_TOONS_SCORES         },
+  { GAME_MODE_PSEUDO_SCORESOLD,                ANIM_CLASS_TOONS_SCORESONLY     },
+  { GAME_MODE_PSEUDO_SCORESNEW,                ANIM_CLASS_TOONS_SCORESONLY     },
+  { GAME_MODE_SCOREINFO,               ANIM_CLASS_TOONS_SCORES         },
   { GAME_MODE_EDITOR,                  ANIM_CLASS_NO_TITLE             },
   { GAME_MODE_PLAYING,                 ANIM_CLASS_NO_TITLE             },
 
@@ -204,7 +234,9 @@ struct AnimClassGameMode
   { ANIM_CLASS_BIT_TITLE_INITIAL,      GAME_MODE_TITLE_INITIAL         },
   { ANIM_CLASS_BIT_TITLE,              GAME_MODE_TITLE                 },
   { ANIM_CLASS_BIT_MAIN,               GAME_MODE_MAIN                  },
+  { ANIM_CLASS_BIT_NAMES,              GAME_MODE_NAMES                 },
   { ANIM_CLASS_BIT_SCORES,             GAME_MODE_SCORES                },
+  { ANIM_CLASS_BIT_SCORESONLY,         GAME_MODE_PSEUDO_SCORESONLY     },
   { ANIM_CLASS_BIT_SUBMENU,            GAME_MODE_PSEUDO_SUBMENU        },
   { ANIM_CLASS_BIT_MENU,               GAME_MODE_PSEUDO_MENU           },
   { ANIM_CLASS_BIT_TOONS,              GAME_MODE_PSEUDO_TOONS          },
@@ -222,6 +254,8 @@ static void ResetGlobalAnim_Clickable(void);
 static void ResetGlobalAnim_Clicked(void);
 
 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
+static struct GlobalAnimPartControlInfo *global_anim_list[MAX_GLOBAL_ANIM_LIST];
+static int num_global_anim_list = 0;
 
 static unsigned int anim_sync_frame = 0;
 
@@ -285,6 +319,12 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
     else
       frame = gfx.anim_random_frame % num_frames;
   }
+  else if (mode & ANIM_LEVEL_NR)       // play frames by level number
+  {
+    int level_pos = level_nr - gfx.anim_first_level;
+
+    frame = level_pos % num_frames;
+  }
   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
   {
     frame = sync_frame % num_frames;
@@ -321,33 +361,42 @@ static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
 static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
 {
   const struct GlobalAnimPartControlInfo *o1 =
-    (struct GlobalAnimPartControlInfo *)obj1;
+    *(struct GlobalAnimPartControlInfo **)obj1;
   const struct GlobalAnimPartControlInfo *o2 =
-    (struct GlobalAnimPartControlInfo *)obj2;
+    *(struct GlobalAnimPartControlInfo **)obj2;
   int compare_result;
 
   if (o1->control_info.draw_order != o2->control_info.draw_order)
     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
+  else if (o1->mode_nr != o2->mode_nr)
+    compare_result = o1->mode_nr - o2->mode_nr;
+  else if (o1->anim_nr != o2->anim_nr)
+    compare_result = o1->anim_nr - o2->anim_nr;
   else
     compare_result = o1->nr - o2->nr;
 
   return compare_result;
 }
 
-static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
+static boolean isPausedOnPlayfieldOrDoor(struct GlobalAnimPartControlInfo *part)
 {
-  const struct GlobalAnimMainControlInfo *o1 =
-    (struct GlobalAnimMainControlInfo *)obj1;
-  const struct GlobalAnimMainControlInfo *o2 =
-    (struct GlobalAnimMainControlInfo *)obj2;
-  int compare_result;
+  // only pause playfield and door animations when playing
+  if (game_status != GAME_MODE_PLAYING)
+    return FALSE;
 
-  if (o1->control_info.draw_order != o2->control_info.draw_order)
-    compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
-  else
-    compare_result = o1->nr - o2->nr;
+  // do not pause animations when game ended (and engine is running)
+  if (checkGameEnded())
+    return FALSE;
 
-  return compare_result;
+  // only pause animations on playfield and doors
+  if (!part->class_playfield_or_door)
+    return FALSE;
+
+  // only pause animations when engine is paused or request dialog is active
+  if (!tape.pausing && !game.request_active)
+    return FALSE;
+
+  return TRUE;
 }
 
 static void InitToonControls(void)
@@ -392,7 +441,8 @@ static void InitToonControls(void)
     int sound = SND_UNDEFINED;
     int music = MUS_UNDEFINED;
     int graphic = IMG_TOON_1 + i;
-    int control = graphic;
+
+    control = graphic;
 
     part->nr = part_nr;
     part->anim_nr = anim_nr;
@@ -418,8 +468,8 @@ static void InitToonControls(void)
     part->initial_anim_sync_frame = 0;
     part->anim_random_frame = -1;
 
-    part->step_delay = 0;
-    part->step_delay_value = graphic_info[control].step_delay;
+    part->step_delay.count = 0;
+    part->step_delay.value = graphic_info[control].step_delay;
 
     part->state = ANIM_STATE_INACTIVE;
     part->last_anim_status = -1;
@@ -525,8 +575,8 @@ static void InitGlobalAnimControls(void)
        part->initial_anim_sync_frame = 0;
        part->anim_random_frame = -1;
 
-       part->step_delay = 0;
-       part->step_delay_value = graphic_info[control].step_delay;
+       part->step_delay.count = 0;
+       part->step_delay.value = graphic_info[control].step_delay;
 
        part->state = ANIM_STATE_INACTIVE;
        part->last_anim_status = -1;
@@ -548,18 +598,14 @@ static void InitGlobalAnimControls(void)
          anim->has_base = TRUE;
        }
 
-       // apply special settings for pointer-style animations
-       if (part->control_info.class == get_hash_from_key("pointer"))
+       // apply special settings to pointer-style animations
+       if (part->control_info.class == get_hash_from_string("pointer"))
        {
-         // force animation to be on top (must set anim and part control)
-         if (anim->control_info.draw_order == 0)
-           anim->control_info.draw_order = 1000000;
-         if (part->control_info.draw_order == 0)
-           part->control_info.draw_order = 1000000;
-
-         // force animation to pass-through clicks (must set part control)
-         if (part->control_info.style == STYLE_DEFAULT)
-           part->control_info.style |= STYLE_PASSTHROUGH;
+         // force pointer-style animations to be checked for clicks first
+         part->control_info.draw_order = 1000000;
+
+         // force pointer-style animations to pass-through clicks
+         part->control_info.style |= STYLE_PASSTHROUGH;
        }
       }
 
@@ -573,26 +619,18 @@ static void InitGlobalAnimControls(void)
 
   InitToonControls();
 
-  // sort all animations according to draw_order and animation number
+  // create list of all animation parts
+  num_global_anim_list = 0;
   for (m = 0; m < NUM_GAME_MODES; m++)
-  {
-    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
-
-    // sort all main animations for this game mode
-    qsort(ctrl->anim, ctrl->num_anims,
-         sizeof(struct GlobalAnimMainControlInfo),
-         compareGlobalAnimMainControlInfo);
+    for (a = 0; a < global_anim_ctrl[m].num_anims; a++)
+      for (p = 0; p < global_anim_ctrl[m].anim[a].num_parts_all; p++)
+       global_anim_list[num_global_anim_list++] =
+         &global_anim_ctrl[m].anim[a].part[p];
 
-    for (a = 0; a < ctrl->num_anims; a++)
-    {
-      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
-
-      // sort all animation parts for this main animation
-      qsort(anim->part, anim->num_parts,
-           sizeof(struct GlobalAnimPartControlInfo),
-           compareGlobalAnimPartControlInfo);
-    }
-  }
+  // sort list of all animation parts according to draw_order and number
+  qsort(global_anim_list, num_global_anim_list,
+       sizeof(struct GlobalAnimPartControlInfo *),
+       compareGlobalAnimPartControlInfo);
 
   for (i = 0; i < NUM_GAME_MODES; i++)
     game_mode_anim_classes[i] = ANIM_CLASS_NONE;
@@ -611,20 +649,143 @@ static void InitGlobalAnimControls(void)
   anim_classes_last = ANIM_CLASS_NONE;
 }
 
+static void SetGlobalAnimEventsForCustomElements(int list_pos)
+{
+  int num_events = GetGlobalAnimEventValueCount(list_pos);
+  int i;
+
+  for (i = 0; i < num_events; i++)
+  {
+    int event = GetGlobalAnimEventValue(list_pos, i);
+
+    if (event & ANIM_EVENT_CE_CHANGE)
+    {
+      int nr = (event >> ANIM_EVENT_CE_BIT) & 0xff;
+
+      if (nr >= 0 && nr < NUM_CUSTOM_ELEMENTS)
+       element_info[EL_CUSTOM_START + nr].has_anim_event = TRUE;
+    }
+  }
+}
+
+void InitGlobalAnimEventsForCustomElements(void)
+{
+  int m, a, p;
+  int control;
+
+  // custom element events for global animations only relevant while playing
+  m = GAME_MODE_PLAYING;
+
+  for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
+  {
+    int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
+
+    control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
+
+    // if no base animation parameters defined, use default values
+    if (control == IMG_UNDEFINED)
+      control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
+
+    SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
+    SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
+
+    for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
+    {
+      control = global_anim_info[ctrl_id].graphic[p][m];
+
+      if (control == IMG_UNDEFINED)
+       continue;
+
+      SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
+      SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
+    }
+  }
+}
+
 void InitGlobalAnimations(void)
 {
   InitGlobalAnimControls();
 }
 
-static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
+static void BlitGlobalAnimation(struct GlobalAnimPartControlInfo *part,
+                               Bitmap *src_bitmap, int src_x0, int src_y0,
+                               int drawing_target)
 {
+  struct GraphicInfo *g = &part->graphic_info;
+  struct GraphicInfo *c = &part->control_info;
+  void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
+    (g->draw_masked ? BlitBitmapMasked : BlitBitmap);
+  void (*blit_screen)(Bitmap *, int, int, int, int, int, int) =
+    (g->draw_masked ? BlitToScreenMasked : BlitToScreen);
   Bitmap *fade_bitmap =
     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
+  int alpha = (c->fade_mode & FADE_MODE_FADE ? part->fade_alpha : g->alpha);
+  int x, y;
+
+  for (y = 0; y < c->stacked_yfactor; y++)
+  {
+    for (x = 0; x < c->stacked_xfactor; x++)
+    {
+      int src_x = src_x0;
+      int src_y = src_y0;
+      int dst_x = part->x + x * (g->width  + c->stacked_xoffset);
+      int dst_y = part->y + y * (g->height + c->stacked_yoffset);
+      int cut_x = 0;
+      int cut_y = 0;
+      int width  = g->width;
+      int height = g->height;
+
+      if (dst_x < 0)
+      {
+       width += dst_x;
+       cut_x = -dst_x;
+       dst_x = 0;
+      }
+      else if (dst_x > part->viewport_width - g->width)
+      {
+       width -= (dst_x - (part->viewport_width - g->width));
+      }
+
+      if (dst_y < 0)
+      {
+       height += dst_y;
+       cut_y  = -dst_y;
+       dst_y = 0;
+      }
+      else if (dst_y > part->viewport_height - g->height)
+      {
+       height -= (dst_y - (part->viewport_height - g->height));
+      }
+
+      if (width <= 0 || height <= 0)
+       continue;
+
+      src_x += cut_x;
+      src_y += cut_y;
+
+      dst_x += part->viewport_x;
+      dst_y += part->viewport_y;
+
+      SetBitmapAlphaNextBlit(src_bitmap, alpha);
+
+      if (drawing_target == DRAW_TO_SCREEN)
+       blit_screen(src_bitmap, src_x, src_y, width, height,
+                   dst_x, dst_y);
+      else
+       blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height,
+                   dst_x, dst_y);
+    }
+  }
+}
+
+static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
+{
   int game_mode_anim_action[NUM_GAME_MODES];
   int mode_nr;
+  int i;
 
-  if (!setup.toons)
+  if (!setup.global_animations)
     return;
 
   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 &&
@@ -715,130 +876,73 @@ static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
     }
   }
 
+  // when restarting global animations, do not redraw them, but stop here
+  if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_RESTART)
+    return;
+
   if (global.anim_status == GAME_MODE_LOADING)
     return;
 
-  for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
+  for (i = 0; i < num_global_anim_list; i++)
   {
-    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
-    int anim_nr;
+    struct GlobalAnimPartControlInfo *part = global_anim_list[i];
+    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
+    struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
+    struct GraphicInfo *g = &part->graphic_info;
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+    int sync_frame;
+    int frame;
+    int last_anim_random_frame = gfx.anim_random_frame;
+
+    if (!setup.toons &&
+       part->graphic >= IMG_TOON_1 &&
+       part->graphic <= IMG_TOON_20)
+      continue;
 
     // when preparing source fading buffer, only draw animations to be stopped
     if (drawing_target == DRAW_TO_FADE_SOURCE &&
-       game_mode_anim_action[mode_nr] != ANIM_STOP)
+       game_mode_anim_action[part->mode_nr] != ANIM_STOP)
       continue;
 
     // when preparing target fading buffer, only draw animations to be started
     if (drawing_target == DRAW_TO_FADE_TARGET &&
-       game_mode_anim_action[mode_nr] != ANIM_START)
+       game_mode_anim_action[part->mode_nr] != ANIM_START)
       continue;
 
-#if 0
-    if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
-       mode_nr != game_status)
+    if (!(anim->state & ANIM_STATE_RUNNING))
       continue;
-#endif
-
-    for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
-    {
-      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
-      struct GraphicInfo *c = &anim->control_info;
-      int part_first, part_last;
-      int part_nr;
-
-      if (!(anim->state & ANIM_STATE_RUNNING))
-       continue;
-
-      part_first = part_last = anim->active_part_nr;
-
-      if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
-      {
-       int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
-
-       part_first = 0;
-       part_last = num_parts - 1;
-      }
-
-      for (part_nr = part_first; part_nr <= part_last; part_nr++)
-      {
-       struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
-       struct GraphicInfo *g = &part->graphic_info;
-       Bitmap *src_bitmap;
-       int src_x, src_y;
-       int width  = g->width;
-       int height = g->height;
-       int dst_x = part->x;
-       int dst_y = part->y;
-       int cut_x = 0;
-       int cut_y = 0;
-       int sync_frame;
-       int frame;
-       void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
-         (g->draw_masked ? BlitBitmapMasked : BlitBitmap);
-       void (*blit_screen)(Bitmap *, int, int, int, int, int, int) =
-         (g->draw_masked ? BlitToScreenMasked : BlitToScreen);
-       int last_anim_random_frame = gfx.anim_random_frame;
-
-       if (!(part->state & ANIM_STATE_RUNNING))
-         continue;
-
-       if (part->drawing_stage != drawing_stage)
-         continue;
 
-       if (part->x < 0)
-       {
-         dst_x = 0;
-         width += part->x;
-         cut_x = -part->x;
-       }
-       else if (part->x > part->viewport_width - g->width)
-         width -= (part->x - (part->viewport_width - g->width));
-
-       if (part->y < 0)
-       {
-         dst_y = 0;
-         height += part->y;
-         cut_y = -part->y;
-       }
-       else if (part->y > part->viewport_height - g->height)
-         height -= (part->y - (part->viewport_height - g->height));
-
-       if (width <= 0 || height <= 0)
-         continue;
+    if (!(part->state & ANIM_STATE_RUNNING))
+      continue;
 
-       dst_x += part->viewport_x;
-       dst_y += part->viewport_y;
+    if (part->drawing_stage != drawing_stage)
+      continue;
 
-       sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
+    // if game is paused, also pause playfield and door animations
+    if (isPausedOnPlayfieldOrDoor(part))
+      part->initial_anim_sync_frame++;
 
-       // re-initialize random animation frame after animation delay
-       if (g->anim_mode == ANIM_RANDOM &&
-           sync_frame % g->anim_delay == 0 &&
-           sync_frame > 0)
-         part->anim_random_frame = GetSimpleRandom(g->anim_frames);
+    sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
 
-       gfx.anim_random_frame = part->anim_random_frame;
+    // re-initialize random animation frame after animation delay
+    if (g->anim_mode == ANIM_RANDOM &&
+       sync_frame % g->anim_delay == 0 &&
+       sync_frame > 0)
+      part->anim_random_frame = GetSimpleRandom(g->anim_frames);
 
-       frame = getAnimationFrame(g->anim_frames, g->anim_delay,
-                                 g->anim_mode, g->anim_start_frame,
-                                 sync_frame);
+    gfx.anim_random_frame = part->anim_random_frame;
 
-       gfx.anim_random_frame = last_anim_random_frame;
+    frame = getAnimationFrame(g->anim_frames, g->anim_delay,
+                             g->anim_mode, g->anim_start_frame,
+                             sync_frame);
 
-       getGlobalAnimGraphicSource(part->graphic, frame, &src_bitmap,
-                                  &src_x, &src_y);
+    gfx.anim_random_frame = last_anim_random_frame;
 
-       src_x += cut_x;
-       src_y += cut_y;
+    getGlobalAnimGraphicSource(part->graphic, frame, &src_bitmap,
+                              &src_x, &src_y);
 
-       if (drawing_target == DRAW_TO_SCREEN)
-         blit_screen(src_bitmap, src_x, src_y, width, height,
-                     dst_x, dst_y);
-       else
-         blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height,
-                     dst_x, dst_y);
-      }
-    }
+    BlitGlobalAnimation(part, src_bitmap, src_x, src_y, drawing_target);
   }
 
   if (drawing_target == DRAW_TO_FADE_TARGET)
@@ -870,8 +974,6 @@ void DrawGlobalAnimations(int drawing_target, int drawing_stage)
     ResetGlobalAnim_Clicked();
   }
 
-  DrawEnvelopeRequestToScreen(drawing_target, drawing_stage);
-
   if (gfx.cursor_mode_override != last_cursor_mode_override)
     SetMouseCursor(gfx.cursor_mode);
 }
@@ -885,15 +987,17 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
   boolean changed = FALSE;
 
   if (part->last_anim_status == global.anim_status &&
-      part->control_info.class != get_hash_from_key("pointer"))
+      part->control_info.class != get_hash_from_string("pointer"))
     return FALSE;
 
   part->last_anim_status = global.anim_status;
 
   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
 
-  if (part->control_info.class == get_hash_from_key("window") ||
-      part->control_info.class == get_hash_from_key("border"))
+  part->class_playfield_or_door = FALSE;
+
+  if (part->control_info.class == get_hash_from_string("window") ||
+      part->control_info.class == get_hash_from_string("border"))
   {
     viewport_x = 0;
     viewport_y = 0;
@@ -902,7 +1006,7 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
 
     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
   }
-  else if (part->control_info.class == get_hash_from_key("pointer"))
+  else if (part->control_info.class == get_hash_from_string("pointer"))
   {
     int mx = MIN(MAX(0, gfx.mouse_x), WIN_XSIZE - 1);
     int my = MIN(MAX(0, gfx.mouse_y), WIN_YSIZE - 1);
@@ -917,20 +1021,22 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
     viewport_width  = part->graphic_info.width;
     viewport_height = part->graphic_info.height;
 
-    part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
+    part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_3;
 
     // do not use global animation mouse pointer when reloading artwork
     if (global.anim_status != GAME_MODE_LOADING)
       gfx.cursor_mode_override = CURSOR_NONE;
   }
-  else if (part->control_info.class == get_hash_from_key("door_1"))
+  else if (part->control_info.class == get_hash_from_string("door_1"))
   {
     viewport_x = DX;
     viewport_y = DY;
     viewport_width  = DXSIZE;
     viewport_height = DYSIZE;
+
+    part->class_playfield_or_door = TRUE;
   }
-  else if (part->control_info.class == get_hash_from_key("door_2"))
+  else if (part->control_info.class == get_hash_from_string("door_2"))
   {
     if (part->mode_nr == GAME_MODE_EDITOR)
     {
@@ -946,6 +1052,8 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
       viewport_width  = VXSIZE;
       viewport_height = VYSIZE;
     }
+
+    part->class_playfield_or_door = TRUE;
   }
   else         // default: "playfield"
   {
@@ -953,6 +1061,8 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
     viewport_y = REAL_SY;
     viewport_width  = FULL_SXSIZE;
     viewport_height = FULL_SYSIZE;
+
+    part->class_playfield_or_door = TRUE;
   }
 
   if (viewport_x != part->viewport_x ||
@@ -965,7 +1075,7 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
     part->viewport_width  = viewport_width;
     part->viewport_height = viewport_height;
 
-    if (part->control_info.class != get_hash_from_key("pointer"))
+    if (part->control_info.class != get_hash_from_string("pointer"))
       changed = TRUE;
   }
 
@@ -1038,6 +1148,13 @@ static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
   if (music == MUS_UNDEFINED)
     return;
 
+  char *anim_music = getMusicInfoEntryFilename(music);
+  char *curr_music = getCurrentlyPlayingMusicFilename();
+
+  // do not stop music if global anim music differs from current music
+  if (!strEqual(curr_music, anim_music))
+    return;
+
   StopMusic();
 
 #if 0
@@ -1087,6 +1204,7 @@ static void PlayGlobalAnimSoundIfLoop(struct GlobalAnimPartControlInfo *part)
 static boolean checkGlobalAnimEvent(int anim_event, int mask)
 {
   int mask_anim_only = mask & ~ANIM_EVENT_PART_MASK;
+  int mask_ce_only   = mask & ~ANIM_EVENT_PAGE_MASK;
 
   if (mask & ANIM_EVENT_ANY)
     return (anim_event & ANIM_EVENT_ANY);
@@ -1094,6 +1212,9 @@ static boolean checkGlobalAnimEvent(int anim_event, int mask)
     return (anim_event & ANIM_EVENT_SELF);
   else if (mask & ANIM_EVENT_UNCLICK_ANY)
     return (anim_event & ANIM_EVENT_UNCLICK_ANY);
+  else if (mask & ANIM_EVENT_CE_CHANGE)
+    return (anim_event == mask ||
+           anim_event == mask_ce_only);
   else
     return (anim_event == mask ||
            anim_event == mask_anim_only);
@@ -1102,67 +1223,116 @@ static boolean checkGlobalAnimEvent(int anim_event, int mask)
 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
 {
   struct GraphicInfo *c = &part->control_info;
-  int num_init_events = GetGlobalAnimEventValueCount(c->init_event);
-  int num_anim_events = GetGlobalAnimEventValueCount(c->anim_event);
   int i;
 
-  for (i = 0; i < num_init_events; i++)
+  if (part->init_event_state)
   {
-    int init_event = GetGlobalAnimEventValue(c->init_event, i);
+    int num_init_events = GetGlobalAnimEventValueCount(c->init_event);
 
-    if (checkGlobalAnimEvent(init_event, mask))
-      return TRUE;
-  }
+    for (i = 0; i < num_init_events; i++)
+    {
+      int init_event = GetGlobalAnimEventValue(c->init_event, i);
 
-  for (i = 0; i < num_anim_events; i++)
+      if (checkGlobalAnimEvent(init_event, mask))
+       return TRUE;
+    }
+  }
+  else if (part->anim_event_state)
   {
-    int anim_event = GetGlobalAnimEventValue(c->anim_event, i);
+    int num_anim_events = GetGlobalAnimEventValueCount(c->anim_event);
+
+    for (i = 0; i < num_anim_events; i++)
+    {
+      int anim_event = GetGlobalAnimEventValue(c->anim_event, i);
 
-    if (checkGlobalAnimEvent(anim_event, mask))
-      return TRUE;
+      if (checkGlobalAnimEvent(anim_event, mask))
+       return TRUE;
+    }
   }
 
   return FALSE;
 }
 
-static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
-                            int mx, int my, boolean clicked)
+static boolean isInsidePartStacked(struct GlobalAnimPartControlInfo *part,
+                                  int mx, int my)
 {
   struct GraphicInfo *g = &part->graphic_info;
+  struct GraphicInfo *c = &part->control_info;
   int part_x = part->viewport_x + part->x;
   int part_y = part->viewport_y + part->y;
   int part_width  = g->width;
   int part_height = g->height;
+  int x, y;
+
+  for (y = 0; y < c->stacked_yfactor; y++)
+  {
+    for (x = 0; x < c->stacked_xfactor; x++)
+    {
+      int part_stacked_x = part_x + x * (part_width  + c->stacked_xoffset);
+      int part_stacked_y = part_y + y * (part_height + c->stacked_yoffset);
+
+      if (mx >= part_stacked_x &&
+         mx <  part_stacked_x + part_width &&
+         my >= part_stacked_y &&
+         my <  part_stacked_y + part_height)
+       return TRUE;
+    }
+  }
 
+  return FALSE;
+}
+
+static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
+                            int mx, int my, boolean clicked)
+{
   // check if mouse click was detected at all
   if (!clicked)
     return FALSE;
 
-  // check if mouse click is inside the animation part's viewport
+  // check if mouse click is outside the animation part's viewport
   if (mx <  part->viewport_x ||
       mx >= part->viewport_x + part->viewport_width ||
       my <  part->viewport_y ||
       my >= part->viewport_y + part->viewport_height)
     return FALSE;
 
-  // check if mouse click is inside the animation part's graphic
-  if (mx <  part_x ||
-      mx >= part_x + part_width ||
-      my <  part_y ||
-      my >= part_y + part_height)
-    return FALSE;
+  // check if mouse click is inside the animation part's (stacked) graphic
+  if (isInsidePartStacked(part, mx, my))
+    return TRUE;
 
-  return TRUE;
+  return FALSE;
 }
 
 static boolean clickBlocked(struct GlobalAnimPartControlInfo *part)
 {
-  return (part->control_info.style & STYLE_BLOCK ? TRUE : FALSE);
+  return ((part->control_info.style & STYLE_BLOCK) ? TRUE : FALSE);
 }
 
 static boolean clickConsumed(struct GlobalAnimPartControlInfo *part)
 {
-  return (part->control_info.style & STYLE_PASSTHROUGH ? FALSE : TRUE);
+  return ((part->control_info.style & STYLE_PASSTHROUGH) ? FALSE : TRUE);
+}
+
+static void SetGlobalAnimPartTileXY(struct GlobalAnimPartControlInfo *part)
+{
+  // calculate playfield position (with scrolling) for related CE tile
+  // (do not use FX/FY, which are incorrect during envelope requests)
+  int FX0 = 2 * TILEX_VAR;     // same as FX during DRAW_TO_FIELDBUFFER
+  int FY0 = 2 * TILEY_VAR;     // same as FY during DRAW_TO_FIELDBUFFER
+  int fx = getFieldbufferOffsetX_RND(ScreenMovDir, ScreenGfxPos);
+  int fy = getFieldbufferOffsetY_RND(ScreenMovDir, ScreenGfxPos);
+  int sx = FX0 + SCREENX(part->tile_x) * TILEX_VAR;
+  int sy = FY0 + SCREENY(part->tile_y) * TILEY_VAR;
+  int cx = SX - REAL_SX;
+  int cy = SY - REAL_SY;
+  int x = sx - fx + cx;
+  int y = sy - fy + cy;
+
+  part->tile_xoffset += part->step_xoffset;
+  part->tile_yoffset += part->step_yoffset;
+
+  part->x = x + part->tile_xoffset;
+  part->y = y + part->tile_yoffset;
 }
 
 static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
@@ -1190,7 +1360,7 @@ static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
     {
       struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
 
-      if (!(part2->state & ANIM_STATE_RUNNING))
+      if (!(part2->state & (ANIM_STATE_RUNNING | ANIM_STATE_WAITING)))
        continue;
 
       if (isClickablePart(part2, mask))
@@ -1232,6 +1402,67 @@ static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
   }
 }
 
+static void InitGlobalAnim_Triggered_ByCustomElement(int nr, int page,
+                                                    int x, int y,
+                                                    int trigger_x,
+                                                    int trigger_y)
+{
+  struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_PLAYING];
+
+  int event_value = ANIM_EVENT_CE_CHANGE;
+  int event_bits = (nr << ANIM_EVENT_CE_BIT) | (page << ANIM_EVENT_PAGE_BIT);
+  int mask = event_value | event_bits;
+  int anim2_nr;
+
+  for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
+  {
+    struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
+    int part2_nr;
+
+    for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
+    {
+      struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
+
+      if (!(part2->state & (ANIM_STATE_RUNNING | ANIM_STATE_WAITING)))
+       continue;
+
+      if (isClickablePart(part2, mask) && !part2->triggered)
+      {
+       struct GraphicInfo *c = &part2->control_info;
+
+       if (c->position == POS_CE ||
+           c->position == POS_CE_TRIGGER)
+       {
+         // store CE tile and offset position to handle scrolling
+         part2->tile_x = (c->position == POS_CE_TRIGGER ? trigger_x : x);
+         part2->tile_y = (c->position == POS_CE_TRIGGER ? trigger_y : y);
+         part2->tile_xoffset = c->x;
+         part2->tile_yoffset = c->y;
+
+         // set resulting animation position relative to CE tile position
+         // (but only for ".init_event", not ".anim_event" type events)
+         if (part2->init_event_state)
+           SetGlobalAnimPartTileXY(part2);
+
+         // restart animation (by using current sync frame)
+         part2->initial_anim_sync_frame = anim_sync_frame;
+       }
+
+       part2->triggered = TRUE;
+
+       // do not trigger any other animation if CE change event was consumed
+       if (c->style == STYLE_CONSUME_CE_EVENT)
+         return;
+
+#if 0
+       Debug("anim:InitGlobalAnim_Triggered_ByCustomElement",
+             "%d.%d TRIGGERED BY CE %d", anim2_nr, part2_nr, nr + 1);
+#endif
+      }
+    }
+  }
+}
+
 static void HandleGlobalAnimDelay(struct GlobalAnimPartControlInfo *part,
                                  int delay_type, char *info_text)
 {
@@ -1270,6 +1501,11 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
   struct GraphicInfo *g = &part->graphic_info;
   struct GraphicInfo *c = &part->control_info;
   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
+  int alpha = (g->alpha != -1 ? g->alpha : SDL_ALPHA_OPAQUE);
+
+  // if game is paused, also pause playfield and door animations
+  if (isPausedOnPlayfieldOrDoor(part))
+    return state;
 
   if (viewport_changed)
     state |= ANIM_STATE_RESTART;
@@ -1295,12 +1531,25 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     part->anim_event_state = (c->anim_event != ANIM_EVENT_UNDEFINED);
 
     part->initial_anim_sync_frame =
-      (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
+      (g->anim_global_sync || g->anim_global_anim_sync ? 0 :
+       anim_sync_frame + part->init_delay_counter);
 
     // do not re-initialize random animation frame after fade-in
     if (part->anim_random_frame == -1)
       part->anim_random_frame = GetSimpleRandom(g->anim_frames);
 
+    if (c->fade_mode & FADE_MODE_FADE)
+    {
+      // when fading in screen, first frame is 100 % transparent or opaque
+      part->fade_delay_counter = c->fade_delay + 1;
+      part->fade_alpha = (c->fade_mode == FADE_MODE_FADE_IN ? 0 : alpha);
+    }
+    else
+    {
+      part->fade_delay_counter = 0;
+      part->fade_alpha = -1;
+    }
+
     if (c->direction & MV_HORIZONTAL)
     {
       int pos_bottom = part->viewport_height - g->height;
@@ -1364,7 +1613,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
       part->step_yoffset = 0;
     }
 
-    if (part->control_info.class != get_hash_from_key("pointer"))
+    if (part->control_info.class != get_hash_from_string("pointer"))
     {
       if (c->x != ARG_UNDEFINED_VALUE)
        part->x = c->x;
@@ -1403,7 +1652,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
       part->init_event_state)
   {
     if (part->initial_anim_sync_frame > 0)
-      part->initial_anim_sync_frame -= part->init_delay_counter - 1;
+      part->initial_anim_sync_frame = anim_sync_frame;
 
     part->init_delay_counter = 1;
     part->init_event_state = FALSE;
@@ -1432,9 +1681,13 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
 
       HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
-    }
 
-    return ANIM_STATE_WAITING;
+      // continue with state ANIM_STATE_RUNNING (set below)
+    }
+    else
+    {
+      return ANIM_STATE_WAITING;
+    }
   }
 
   if (part->init_event_state)
@@ -1510,11 +1763,18 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     return ANIM_STATE_WAITING;
   }
 
+  if (part->fade_delay_counter > 0)
+  {
+    part->fade_delay_counter--;
+    part->fade_alpha = alpha * (c->fade_mode == FADE_MODE_FADE_IN ?
+                               c->fade_delay - part->fade_delay_counter :
+                               part->fade_delay_counter) / c->fade_delay;
+  }
+
   // special case to prevent expiring loop sounds when playing
   PlayGlobalAnimSoundIfLoop(part);
 
-  if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
-                      anim_sync_frame))
+  if (!DelayReachedExt(&part->step_delay, anim_sync_frame))
     return ANIM_STATE_RUNNING;
 
 #if 0
@@ -1529,8 +1789,16 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
   }
 #endif
 
-  part->x += part->step_xoffset;
-  part->y += part->step_yoffset;
+  if (c->position == POS_CE ||
+      c->position == POS_CE_TRIGGER)
+  {
+    SetGlobalAnimPartTileXY(part);
+  }
+  else
+  {
+    part->x += part->step_xoffset;
+    part->y += part->step_yoffset;
+  }
 
   anim->last_x = part->x;
   anim->last_y = part->y;
@@ -1653,9 +1921,13 @@ static void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim,
   for (i = 0; i < num_parts; i++)
     anim->part[i].state = ANIM_STATE_INACTIVE;
 
-  // ... then set current animation parts to "running"
+  // ... then set current animation part to "running" ...
   part->state = ANIM_STATE_RUNNING;
 
+  // ... unless it is waiting for an initial event
+  if (part->init_event_state)
+    part->state = ANIM_STATE_WAITING;
+
   anim->state = HandleGlobalAnim_Part(part, anim->state);
 
   if (anim->state & ANIM_STATE_RESTART)
@@ -1757,7 +2029,10 @@ static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part)
   if (event_action == ANIM_EVENT_ACTION_NONE)
     return FALSE;
 
-  PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
+  if (event_action < MAX_IMAGE_FILES)
+    PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
+  else
+    OpenURLFromHash(anim_url_hash, event_action);
 
   // check if further actions are allowed to be executed
   if (part->control_info.style & STYLE_MULTIPLE_ACTIONS)
@@ -1768,29 +2043,17 @@ static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part)
 
 static void InitGlobalAnim_Clickable(void)
 {
-  int mode_nr;
+  int i;
 
-  for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
+  for (i = 0; i < num_global_anim_list; i++)
   {
-    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
-    int anim_nr;
-
-    for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
-    {
-      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
-      int part_nr;
-
-      for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
-      {
-       struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
+    struct GlobalAnimPartControlInfo *part = global_anim_list[i];
 
-       if (part->triggered)
-         part->clicked = TRUE;
+    if (part->triggered)
+      part->clicked = TRUE;
 
-       part->triggered = FALSE;
-       part->clickable = FALSE;
-      }
-    }
+    part->triggered = FALSE;
+    part->clickable = FALSE;
   }
 }
 
@@ -1804,103 +2067,93 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
   boolean anything_clicked = FALSE;
   boolean any_part_clicked = FALSE;
   boolean any_event_action = FALSE;
-  int mode_nr;
   int i;
 
-  // check game modes in reverse draw order (to stop when clicked)
-  for (mode_nr = NUM_GAME_MODES - 1; mode_nr >= 0; mode_nr--)
+  // check animation parts in reverse draw order (to stop when clicked)
+  for (i = num_global_anim_list - 1; i >= 0; i--)
   {
-    struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
-    int anim_nr;
+    struct GlobalAnimPartControlInfo *part = global_anim_list[i];
 
-    // check animations in reverse draw order (to stop when clicked)
-    for (anim_nr = ctrl->num_anims - 1; anim_nr >= 0; anim_nr--)
-    {
-      struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
-      int part_nr;
-
-      // check animation parts in reverse draw order (to stop when clicked)
-      for (part_nr = anim->num_parts_all - 1; part_nr >= 0; part_nr--)
-      {
-       struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
+    // if request dialog is active, only handle pointer-style animations
+    if (game.request_active &&
+       part->control_info.class != get_hash_from_string("pointer"))
+      continue;
 
-       if (clicked_event == ANIM_CLICKED_RESET)
-       {
-         part->clicked = FALSE;
+    if (clicked_event == ANIM_CLICKED_RESET)
+    {
+      part->clicked = FALSE;
 
-         continue;
-       }
+      continue;
+    }
 
-       if (!part->clickable)
-         continue;
+    if (!part->clickable)
+      continue;
 
-       if (!(part->state & ANIM_STATE_RUNNING))
-         continue;
+    if (!(part->state & ANIM_STATE_RUNNING))
+      continue;
 
-       // always handle "any" click events (clicking anywhere on screen) ...
-       if (clicked_event == ANIM_CLICKED_PRESSED &&
-           isClickablePart(part, ANIM_EVENT_ANY))
-       {
+    // always handle "any" click events (clicking anywhere on screen) ...
+    if (clicked_event == ANIM_CLICKED_PRESSED &&
+       isClickablePart(part, ANIM_EVENT_ANY))
+    {
 #if DEBUG_ANIM_EVENTS
-         Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY ANY",
-               part->old_anim_nr + 1, part->old_nr + 1);
+      Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY ANY",
+           part->old_anim_nr + 1, part->old_nr + 1);
 #endif
 
-         anything_clicked = part->clicked = TRUE;
-         click_consumed |= clickConsumed(part);
-       }
+      anything_clicked = part->clicked = TRUE;
+      click_consumed |= clickConsumed(part);
+    }
 
-       // always handle "unclick:any" events (releasing anywhere on screen) ...
-       if (clicked_event == ANIM_CLICKED_RELEASED &&
-           isClickablePart(part, ANIM_EVENT_UNCLICK_ANY))
-       {
+    // always handle "unclick:any" events (releasing anywhere on screen) ...
+    if (clicked_event == ANIM_CLICKED_RELEASED &&
+       isClickablePart(part, ANIM_EVENT_UNCLICK_ANY))
+    {
 #if DEBUG_ANIM_EVENTS
-         Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY UNCLICK:ANY",
-               part->old_anim_nr + 1, part->old_nr + 1);
+      Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY UNCLICK:ANY",
+           part->old_anim_nr + 1, part->old_nr + 1);
 #endif
 
-         anything_clicked = part->clicked = TRUE;
-         click_consumed |= clickConsumed(part);
-       }
+      anything_clicked = part->clicked = TRUE;
+      click_consumed |= clickConsumed(part);
+    }
 
-       // ... but only handle the first (topmost) clickable animation
-       if (any_part_clicked)
-         continue;
+    // ... but only handle the first (topmost) clickable animation
+    if (any_part_clicked)
+      continue;
 
-       if (clicked_event == ANIM_CLICKED_PRESSED &&
-           isClickedPart(part, mx, my, TRUE))
-       {
+    if (clicked_event == ANIM_CLICKED_PRESSED &&
+       isClickedPart(part, mx, my, TRUE))
+    {
 #if 0
-         Debug("anim:InitGlobalAnim_Clicked", "%d.%d CLICKED [%d]",
-               anim_nr, part_nr, part->control_info.anim_event_action);
+      Debug("anim:InitGlobalAnim_Clicked", "%d.%d CLICKED [%d]",
+           anim_nr, part_nr, part->control_info.anim_event_action);
 #endif
 
-         // after executing event action, ignore any further actions
-         if (!any_event_action && DoGlobalAnim_EventAction(part))
-           any_event_action = TRUE;
+      // after executing event action, ignore any further actions
+      if (!any_event_action && DoGlobalAnim_EventAction(part))
+       any_event_action = TRUE;
 
-         // determine if mouse clicks should be blocked from other animations
-         any_part_clicked |= clickConsumed(part);
+      // determine if mouse clicks should be blocked from other animations
+      any_part_clicked |= clickConsumed(part);
 
-         if (isClickablePart(part, ANIM_EVENT_SELF))
-         {
+      if (isClickablePart(part, ANIM_EVENT_SELF))
+      {
 #if DEBUG_ANIM_EVENTS
-           Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY SELF",
-                 part->old_anim_nr + 1, part->old_nr + 1);
+       Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY SELF",
+             part->old_anim_nr + 1, part->old_nr + 1);
 #endif
 
-           anything_clicked = part->clicked = TRUE;
-           click_consumed |= clickConsumed(part);
-         }
+       anything_clicked = part->clicked = TRUE;
+       click_consumed |= clickConsumed(part);
+      }
 
-         // determine if mouse clicks should be blocked by this animation
-         click_consumed |= clickBlocked(part);
+      // determine if mouse clicks should be blocked by this animation
+      click_consumed |= clickBlocked(part);
 
-         // check if this click is defined to trigger other animations
-         InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
-                                  ANIM_EVENT_CLICK, "CLICK");
-       }
-      }
+      // check if this click is defined to trigger other animations
+      InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
+                              ANIM_EVENT_CLICK, "CLICK");
     }
   }
 
@@ -1930,6 +2183,23 @@ static void ResetGlobalAnim_Clicked(void)
   InitGlobalAnim_Clicked(-1, -1, ANIM_CLICKED_RESET);
 }
 
+void RestartGlobalAnimsByStatus(int status)
+{
+  int anim_status_last = global.anim_status;
+
+  global.anim_status = status;
+
+  // force restarting global animations by changed global animation status
+  DrawGlobalAnimationsExt(DRAW_TO_SCREEN, DRAW_GLOBAL_ANIM_STAGE_RESTART);
+
+  global.anim_status = anim_status_last;
+}
+
+void SetAnimStatusBeforeFading(int status)
+{
+  anim_status_last_before_fading = status;
+}
+
 boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
 {
   static boolean click_consumed = FALSE;
@@ -1960,3 +2230,19 @@ boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
 
   return click_consumed_current;
 }
+
+int getGlobalAnimSyncFrame(void)
+{
+  return anim_sync_frame;
+}
+
+void HandleGlobalAnimEventByElementChange(int element, int page, int x, int y,
+                                         int trigger_x, int trigger_y)
+{
+  if (!IS_CUSTOM_ELEMENT(element))
+    return;
+
+  // custom element stored as 0 to 255, change page stored as 1 to 32
+  InitGlobalAnim_Triggered_ByCustomElement(element - EL_CUSTOM_START, page + 1,
+                                          x, y, trigger_x, trigger_y);
+}
index 5c5b7895456569b5cd5e5e88cf2fb6b726cc5724..274cade99dc0c8a41c839a52518ef5033379f118 100644 (file)
 
 int getAnimationFrame(int, int, int, int, int);
 
+void InitGlobalAnimEventsForCustomElements(void);
 void InitGlobalAnimations(void);
 void DrawGlobalAnimations(int, int);
 
+void RestartGlobalAnimsByStatus(int);
+void SetAnimStatusBeforeFading(int);
+
 boolean HandleGlobalAnimClicks(int, int, int, boolean);
+void HandleGlobalAnimEventByElementChange(int, int, int, int, int, int);
+
+int getGlobalAnimSyncFrame(void);
 
 #endif
diff --git a/src/api.c b/src/api.c
new file mode 100644 (file)
index 0000000..3e2b387
--- /dev/null
+++ b/src/api.c
@@ -0,0 +1,1269 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2022 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// api.c
+// ============================================================================
+
+#include "libgame/libgame.h"
+
+#include "api.h"
+#include "main.h"
+#include "files.h"
+#include "config.h"
+
+
+// ============================================================================
+// generic helper functions
+// ============================================================================
+
+static void ExecuteAsThread(SDL_ThreadFunction function, char *name, void *data,
+                           char *error)
+{
+#if defined(PLATFORM_EMSCRIPTEN)
+  // threads currently not fully supported by Emscripten/SDL and some browsers
+  function(data);
+#else
+  SDL_Thread *thread = SDL_CreateThread(function, name, data);
+
+  if (thread != NULL)
+    SDL_DetachThread(thread);
+  else
+    Error("Cannot create thread to %s!", error);
+
+  // nasty kludge to lower probability of intermingled thread error messages
+  Delay(1);
+#endif
+}
+
+static char *getPasswordJSON(char *password)
+{
+  static char password_json[MAX_FILENAME_LEN] = "";
+  static boolean initialized = FALSE;
+
+  if (!initialized)
+  {
+    if (password != NULL &&
+       !strEqual(password, "") &&
+       !strEqual(password, UNDEFINED_PASSWORD))
+      snprintf(password_json, MAX_FILENAME_LEN,
+              "  \"password\":             \"%s\",\n",
+              setup.api_server_password);
+
+    initialized = TRUE;
+  }
+
+  return password_json;
+}
+
+static char *getFileBase64(char *filename)
+{
+  struct stat file_status;
+
+  if (stat(filename, &file_status) != 0)
+  {
+    Error("cannot stat file '%s'", filename);
+
+    return NULL;
+  }
+
+  int buffer_size = file_status.st_size;
+  byte *buffer = checked_malloc(buffer_size);
+  FILE *file;
+  int i;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    Error("cannot open file '%s'", filename);
+
+    checked_free(buffer);
+
+    return NULL;
+  }
+
+  for (i = 0; i < buffer_size; i++)
+  {
+    int c = fgetc(file);
+
+    if (c == EOF)
+    {
+      Error("cannot read from input file '%s'", filename);
+
+      fclose(file);
+      checked_free(buffer);
+
+      return NULL;
+    }
+
+    buffer[i] = (byte)c;
+  }
+
+  fclose(file);
+
+  int buffer_encoded_size = base64_encoded_size(buffer_size);
+  char *buffer_encoded = checked_malloc(buffer_encoded_size);
+
+  base64_encode(buffer_encoded, buffer, buffer_size);
+
+  checked_free(buffer);
+
+  return buffer_encoded;
+}
+
+
+// ============================================================================
+// add score API functions
+// ============================================================================
+
+struct ApiAddScoreThreadData
+{
+  int level_nr;
+  boolean tape_saved;
+  char *leveldir_subdir;
+  char *score_tape_filename;
+  struct ScoreEntry score_entry;
+};
+
+static void *CreateThreadData_ApiAddScore(int nr, boolean tape_saved,
+                                         char *score_tape_filename)
+{
+  struct ApiAddScoreThreadData *data =
+    checked_malloc(sizeof(struct ApiAddScoreThreadData));
+  struct ScoreEntry *score_entry = &scores.entry[scores.last_added];
+
+  if (score_tape_filename == NULL)
+    score_tape_filename = getScoreTapeFilename(score_entry->tape_basename, nr);
+
+  data->level_nr = nr;
+  data->tape_saved = tape_saved;
+  data->leveldir_subdir = getStringCopy(leveldir_current->subdir);
+  data->score_tape_filename = getStringCopy(score_tape_filename);
+  data->score_entry = *score_entry;
+
+  return data;
+}
+
+static void FreeThreadData_ApiAddScore(void *data_raw)
+{
+  struct ApiAddScoreThreadData *data = data_raw;
+
+  checked_free(data->leveldir_subdir);
+  checked_free(data->score_tape_filename);
+  checked_free(data);
+}
+
+static boolean SetRequest_ApiAddScore(struct HttpRequest *request,
+                                     void *data_raw)
+{
+  struct ApiAddScoreThreadData *data = data_raw;
+  struct ScoreEntry *score_entry = &data->score_entry;
+  char *score_tape_filename = data->score_tape_filename;
+  boolean tape_saved = data->tape_saved;
+  int level_nr = data->level_nr;
+
+  request->hostname = setup.api_server_hostname;
+  request->port     = API_SERVER_PORT;
+  request->method   = API_SERVER_METHOD;
+  request->uri      = API_SERVER_URI_ADD;
+
+  char *tape_base64 = getFileBase64(score_tape_filename);
+
+  if (tape_base64 == NULL)
+  {
+    Error("loading and base64 encoding score tape file failed");
+
+    return FALSE;
+  }
+
+  char *player_name_raw = score_entry->name;
+  char *player_uuid_raw = setup.player_uuid;
+
+  if (options.player_name != NULL && global.autoplay_leveldir != NULL)
+  {
+    player_name_raw = options.player_name;
+    player_uuid_raw = "";
+  }
+
+  char *levelset_identifier = getEscapedJSON(leveldir_current->identifier);
+  char *levelset_name       = getEscapedJSON(leveldir_current->name);
+  char *levelset_author     = getEscapedJSON(leveldir_current->author);
+  char *level_name          = getEscapedJSON(level.name);
+  char *level_author        = getEscapedJSON(level.author);
+  char *player_name         = getEscapedJSON(player_name_raw);
+  char *player_uuid         = getEscapedJSON(player_uuid_raw);
+
+  snprintf(request->body, MAX_HTTP_BODY_SIZE,
+          "{\n"
+          "%s"
+          "  \"game_version\":         \"%s\",\n"
+          "  \"game_platform\":        \"%s\",\n"
+          "  \"batch_time\":           \"%d\",\n"
+          "  \"levelset_identifier\":  \"%s\",\n"
+          "  \"levelset_name\":        \"%s\",\n"
+          "  \"levelset_author\":      \"%s\",\n"
+          "  \"levelset_num_levels\":  \"%d\",\n"
+          "  \"levelset_first_level\": \"%d\",\n"
+          "  \"level_nr\":             \"%d\",\n"
+          "  \"level_name\":           \"%s\",\n"
+          "  \"level_author\":         \"%s\",\n"
+          "  \"use_step_counter\":     \"%d\",\n"
+          "  \"rate_time_over_score\": \"%d\",\n"
+          "  \"player_name\":          \"%s\",\n"
+          "  \"player_uuid\":          \"%s\",\n"
+          "  \"score\":                \"%d\",\n"
+          "  \"time\":                 \"%d\",\n"
+          "  \"tape_basename\":        \"%s\",\n"
+          "  \"tape_saved\":           \"%d\",\n"
+          "  \"tape\":                 \"%s\"\n"
+          "}\n",
+          getPasswordJSON(setup.api_server_password),
+          getProgramRealVersionString(),
+          getProgramPlatformString(),
+          (int)global.autoplay_time,
+          levelset_identifier,
+          levelset_name,
+          levelset_author,
+          leveldir_current->levels,
+          leveldir_current->first_level,
+          level_nr,
+          level_name,
+          level_author,
+          level.use_step_counter,
+          level.rate_time_over_score,
+          player_name,
+          player_uuid,
+          score_entry->score,
+          score_entry->time,
+          score_entry->tape_basename,
+          tape_saved,
+          tape_base64);
+
+  checked_free(tape_base64);
+
+  checked_free(levelset_identifier);
+  checked_free(levelset_name);
+  checked_free(levelset_author);
+  checked_free(level_name);
+  checked_free(level_author);
+  checked_free(player_name);
+  checked_free(player_uuid);
+
+  ConvertHttpRequestBodyToServerEncoding(request);
+
+  return TRUE;
+}
+
+static void HandleResponse_ApiAddScore(struct HttpResponse *response,
+                                      void *data_raw)
+{
+  server_scores.uploaded = TRUE;
+}
+
+static void HandleFailure_ApiAddScore(void *data_raw)
+{
+  struct ApiAddScoreThreadData *data = data_raw;
+
+  PrepareScoreTapesForUpload(data->leveldir_subdir);
+}
+
+#if defined(PLATFORM_EMSCRIPTEN)
+static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw,
+                                         void *buffer, unsigned int size)
+{
+  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+
+  if (response != NULL)
+  {
+    HandleResponse_ApiAddScore(response, data_raw);
+
+    checked_free(response);
+  }
+  else
+  {
+    Error("server response too large to handle (%d bytes)", size);
+
+    HandleFailure_ApiAddScore(data_raw);
+  }
+
+  FreeThreadData_ApiAddScore(data_raw);
+}
+
+static void Emscripten_ApiAddScore_Failed(unsigned handle, void *data_raw,
+                                         int code, const char *status)
+{
+  Error("server failed to handle request: %d %s", code, status);
+
+  HandleFailure_ApiAddScore(data_raw);
+
+  FreeThreadData_ApiAddScore(data_raw);
+}
+
+static void Emscripten_ApiAddScore_Progress(unsigned handle, void *data_raw,
+                                           int bytes, int size)
+{
+  // nothing to do here
+}
+
+static void Emscripten_ApiAddScore_HttpRequest(struct HttpRequest *request,
+                                              void *data_raw)
+{
+  if (!SetRequest_ApiAddScore(request, data_raw))
+  {
+    FreeThreadData_ApiAddScore(data_raw);
+
+    return;
+  }
+
+  emscripten_async_wget2_data(request->uri,
+                             request->method,
+                             request->body,
+                             data_raw,
+                             TRUE,
+                             Emscripten_ApiAddScore_Loaded,
+                             Emscripten_ApiAddScore_Failed,
+                             Emscripten_ApiAddScore_Progress);
+}
+
+#else
+
+static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
+                                      struct HttpResponse *response,
+                                      void *data_raw)
+{
+  if (!SetRequest_ApiAddScore(request, data_raw))
+    return;
+
+  if (!DoHttpRequest(request, response))
+  {
+    Error("HTTP request failed: %s", GetHttpError());
+
+    HandleFailure_ApiAddScore(data_raw);
+
+    return;
+  }
+
+  if (!HTTP_SUCCESS(response->status_code))
+  {
+    Error("server failed to handle request: %d %s",
+         response->status_code,
+         response->status_text);
+
+    HandleFailure_ApiAddScore(data_raw);
+
+    return;
+  }
+
+  HandleResponse_ApiAddScore(response, data_raw);
+}
+
+static void ApiAddScore_HttpRequest(struct HttpRequest *request,
+                                   struct HttpResponse *response,
+                                   void *data_raw)
+{
+  ApiAddScore_HttpRequestExt(request, response, data_raw);
+
+  FreeThreadData_ApiAddScore(data_raw);
+}
+#endif
+
+static int ApiAddScoreThread(void *data_raw)
+{
+  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  program.api_thread_count++;
+
+#if defined(PLATFORM_EMSCRIPTEN)
+  Emscripten_ApiAddScore_HttpRequest(request, data_raw);
+#else
+  ApiAddScore_HttpRequest(request, response, data_raw);
+#endif
+
+  program.api_thread_count--;
+
+  checked_free(request);
+  checked_free(response);
+
+  return 0;
+}
+
+void ApiAddScoreAsThread(int nr, boolean tape_saved, char *score_tape_filename)
+{
+  struct ApiAddScoreThreadData *data =
+    CreateThreadData_ApiAddScore(nr, tape_saved, score_tape_filename);
+
+  ExecuteAsThread(ApiAddScoreThread,
+                 "ApiAddScore", data,
+                 "upload score to server");
+}
+
+
+// ============================================================================
+// get score API functions
+// ============================================================================
+
+struct ApiGetScoreThreadData
+{
+  int level_nr;
+  char *score_cache_filename;
+};
+
+static void *CreateThreadData_ApiGetScore(int nr)
+{
+  struct ApiGetScoreThreadData *data =
+    checked_malloc(sizeof(struct ApiGetScoreThreadData));
+  char *score_cache_filename = getScoreCacheFilename(nr);
+
+  data->level_nr = nr;
+  data->score_cache_filename = getStringCopy(score_cache_filename);
+
+  return data;
+}
+
+static void FreeThreadData_ApiGetScore(void *data_raw)
+{
+  struct ApiGetScoreThreadData *data = data_raw;
+
+  checked_free(data->score_cache_filename);
+  checked_free(data);
+}
+
+static boolean SetRequest_ApiGetScore(struct HttpRequest *request,
+                                     void *data_raw)
+{
+  struct ApiGetScoreThreadData *data = data_raw;
+  int level_nr = data->level_nr;
+
+  request->hostname = setup.api_server_hostname;
+  request->port     = API_SERVER_PORT;
+  request->method   = API_SERVER_METHOD;
+  request->uri      = API_SERVER_URI_GET;
+
+  char *levelset_identifier = getEscapedJSON(leveldir_current->identifier);
+  char *levelset_name       = getEscapedJSON(leveldir_current->name);
+
+  snprintf(request->body, MAX_HTTP_BODY_SIZE,
+          "{\n"
+          "%s"
+          "  \"game_version\":         \"%s\",\n"
+          "  \"game_platform\":        \"%s\",\n"
+          "  \"levelset_identifier\":  \"%s\",\n"
+          "  \"levelset_name\":        \"%s\",\n"
+          "  \"level_nr\":             \"%d\"\n"
+          "}\n",
+          getPasswordJSON(setup.api_server_password),
+          getProgramRealVersionString(),
+          getProgramPlatformString(),
+          levelset_identifier,
+          levelset_name,
+          level_nr);
+
+  checked_free(levelset_identifier);
+  checked_free(levelset_name);
+
+  ConvertHttpRequestBodyToServerEncoding(request);
+
+  return TRUE;
+}
+
+static void HandleResponse_ApiGetScore(struct HttpResponse *response,
+                                      void *data_raw)
+{
+  struct ApiGetScoreThreadData *data = data_raw;
+
+  if (response->body_size == 0)
+  {
+    // no scores available for this level
+
+    return;
+  }
+
+  ConvertHttpResponseBodyToClientEncoding(response);
+
+  char *filename = data->score_cache_filename;
+  FILE *file;
+  int i;
+
+  // used instead of "leveldir_current->subdir" (for network games)
+  InitScoreCacheDirectory(levelset.identifier);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Warn("cannot save score cache file '%s'", filename);
+
+    return;
+  }
+
+  for (i = 0; i < response->body_size; i++)
+    fputc(response->body[i], file);
+
+  fclose(file);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+
+  server_scores.updated = TRUE;
+}
+
+#if defined(PLATFORM_EMSCRIPTEN)
+static void Emscripten_ApiGetScore_Loaded(unsigned handle, void *data_raw,
+                                         void *buffer, unsigned int size)
+{
+  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+
+  if (response != NULL)
+  {
+    HandleResponse_ApiGetScore(response, data_raw);
+
+    checked_free(response);
+  }
+  else
+  {
+    Error("server response too large to handle (%d bytes)", size);
+  }
+
+  FreeThreadData_ApiGetScore(data_raw);
+}
+
+static void Emscripten_ApiGetScore_Failed(unsigned handle, void *data_raw,
+                                         int code, const char *status)
+{
+  Error("server failed to handle request: %d %s", code, status);
+
+  FreeThreadData_ApiGetScore(data_raw);
+}
+
+static void Emscripten_ApiGetScore_Progress(unsigned handle, void *data_raw,
+                                           int bytes, int size)
+{
+  // nothing to do here
+}
+
+static void Emscripten_ApiGetScore_HttpRequest(struct HttpRequest *request,
+                                              void *data_raw)
+{
+  if (!SetRequest_ApiGetScore(request, data_raw))
+  {
+    FreeThreadData_ApiGetScore(data_raw);
+
+    return;
+  }
+
+  emscripten_async_wget2_data(request->uri,
+                             request->method,
+                             request->body,
+                             data_raw,
+                             TRUE,
+                             Emscripten_ApiGetScore_Loaded,
+                             Emscripten_ApiGetScore_Failed,
+                             Emscripten_ApiGetScore_Progress);
+}
+
+#else
+
+static void ApiGetScore_HttpRequestExt(struct HttpRequest *request,
+                                      struct HttpResponse *response,
+                                      void *data_raw)
+{
+  if (!SetRequest_ApiGetScore(request, data_raw))
+    return;
+
+  if (!DoHttpRequest(request, response))
+  {
+    Error("HTTP request failed: %s", GetHttpError());
+
+    return;
+  }
+
+  if (!HTTP_SUCCESS(response->status_code))
+  {
+    // do not show error message if no scores found for this level set
+    if (response->status_code == 404)
+      return;
+
+    Error("server failed to handle request: %d %s",
+         response->status_code,
+         response->status_text);
+
+    return;
+  }
+
+  HandleResponse_ApiGetScore(response, data_raw);
+}
+
+static void ApiGetScore_HttpRequest(struct HttpRequest *request,
+                                   struct HttpResponse *response,
+                                   void *data_raw)
+{
+  ApiGetScore_HttpRequestExt(request, response, data_raw);
+
+  FreeThreadData_ApiGetScore(data_raw);
+}
+#endif
+
+static int ApiGetScoreThread(void *data_raw)
+{
+  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  program.api_thread_count++;
+
+#if defined(PLATFORM_EMSCRIPTEN)
+  Emscripten_ApiGetScore_HttpRequest(request, data_raw);
+#else
+  ApiGetScore_HttpRequest(request, response, data_raw);
+#endif
+
+  program.api_thread_count--;
+
+  checked_free(request);
+  checked_free(response);
+
+  return 0;
+}
+
+void ApiGetScoreAsThread(int nr)
+{
+  struct ApiGetScoreThreadData *data = CreateThreadData_ApiGetScore(nr);
+
+  ExecuteAsThread(ApiGetScoreThread,
+                 "ApiGetScore", data,
+                 "download scores from server");
+}
+
+
+// ============================================================================
+// get score tape API functions
+// ============================================================================
+
+struct ApiGetScoreTapeThreadData
+{
+  int level_nr;
+  int score_id;
+  char *score_tape_filename;
+};
+
+static void *CreateThreadData_ApiGetScoreTape(int nr, int id,
+                                             char *score_tape_basename)
+{
+  struct ApiGetScoreTapeThreadData *data =
+    checked_malloc(sizeof(struct ApiGetScoreTapeThreadData));
+  char *score_tape_filename = getScoreCacheTapeFilename(score_tape_basename, nr);
+
+  data->level_nr = nr;
+  data->score_id = id;
+  data->score_tape_filename = getStringCopy(score_tape_filename);
+
+  return data;
+}
+
+static void FreeThreadData_ApiGetScoreTape(void *data_raw)
+{
+  struct ApiGetScoreTapeThreadData *data = data_raw;
+
+  checked_free(data->score_tape_filename);
+  checked_free(data);
+}
+
+static boolean SetRequest_ApiGetScoreTape(struct HttpRequest *request,
+                                          void *data_raw)
+{
+  struct ApiGetScoreTapeThreadData *data = data_raw;
+  int score_id = data->score_id;
+
+  request->hostname = setup.api_server_hostname;
+  request->port     = API_SERVER_PORT;
+  request->method   = API_SERVER_METHOD;
+  request->uri      = API_SERVER_URI_GETTAPE;
+
+  snprintf(request->body, MAX_HTTP_BODY_SIZE,
+          "{\n"
+          "%s"
+          "  \"game_version\":         \"%s\",\n"
+          "  \"game_platform\":        \"%s\",\n"
+          "  \"id\":                   \"%d\"\n"
+          "}\n",
+          getPasswordJSON(setup.api_server_password),
+          getProgramRealVersionString(),
+          getProgramPlatformString(),
+          score_id);
+
+  ConvertHttpRequestBodyToServerEncoding(request);
+
+  return TRUE;
+}
+
+static void HandleResponse_ApiGetScoreTape(struct HttpResponse *response,
+                                           void *data_raw)
+{
+  struct ApiGetScoreTapeThreadData *data = data_raw;
+
+  if (response->body_size == 0)
+  {
+    // no score tape available for this level
+
+    return;
+  }
+
+  // (do not convert HTTP response body, as it contains binary data here)
+
+  int level_nr = data->level_nr;
+  char *filename = data->score_tape_filename;
+  FILE *file;
+  int i;
+
+  // used instead of "leveldir_current->subdir" (for network games)
+  InitScoreCacheTapeDirectory(levelset.identifier, level_nr);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Warn("cannot save score tape file '%s'", filename);
+
+    return;
+  }
+
+  for (i = 0; i < response->body_size; i++)
+    fputc(response->body[i], file);
+
+  fclose(file);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+
+  server_scores.tape_downloaded = TRUE;
+}
+
+#if defined(PLATFORM_EMSCRIPTEN)
+static void Emscripten_ApiGetScoreTape_Loaded(unsigned handle, void *data_raw,
+                                              void *buffer, unsigned int size)
+{
+  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+
+  if (response != NULL)
+  {
+    HandleResponse_ApiGetScoreTape(response, data_raw);
+
+    checked_free(response);
+  }
+  else
+  {
+    Error("server response too large to handle (%d bytes)", size);
+  }
+
+  FreeThreadData_ApiGetScoreTape(data_raw);
+}
+
+static void Emscripten_ApiGetScoreTape_Failed(unsigned handle, void *data_raw,
+                                              int code, const char *status)
+{
+  Error("server failed to handle request: %d %s", code, status);
+
+  FreeThreadData_ApiGetScoreTape(data_raw);
+}
+
+static void Emscripten_ApiGetScoreTape_Progress(unsigned handle, void *data_raw,
+                                                int bytes, int size)
+{
+  // nothing to do here
+}
+
+static void Emscripten_ApiGetScoreTape_HttpRequest(struct HttpRequest *request,
+                                                   void *data_raw)
+{
+  if (!SetRequest_ApiGetScoreTape(request, data_raw))
+  {
+    FreeThreadData_ApiGetScoreTape(data_raw);
+
+    return;
+  }
+
+  emscripten_async_wget2_data(request->uri,
+                             request->method,
+                             request->body,
+                             data_raw,
+                             TRUE,
+                             Emscripten_ApiGetScoreTape_Loaded,
+                             Emscripten_ApiGetScoreTape_Failed,
+                             Emscripten_ApiGetScoreTape_Progress);
+}
+
+#else
+
+static void ApiGetScoreTape_HttpRequestExt(struct HttpRequest *request,
+                                           struct HttpResponse *response,
+                                           void *data_raw)
+{
+  if (!SetRequest_ApiGetScoreTape(request, data_raw))
+    return;
+
+  if (!DoHttpRequest(request, response))
+  {
+    Error("HTTP request failed: %s", GetHttpError());
+
+    return;
+  }
+
+  if (!HTTP_SUCCESS(response->status_code))
+  {
+    // do not show error message if no scores found for this level set
+    if (response->status_code == 404)
+      return;
+
+    Error("server failed to handle request: %d %s",
+         response->status_code,
+         response->status_text);
+
+    return;
+  }
+
+  HandleResponse_ApiGetScoreTape(response, data_raw);
+}
+
+static void ApiGetScoreTape_HttpRequest(struct HttpRequest *request,
+                                        struct HttpResponse *response,
+                                        void *data_raw)
+{
+  ApiGetScoreTape_HttpRequestExt(request, response, data_raw);
+
+  FreeThreadData_ApiGetScoreTape(data_raw);
+}
+#endif
+
+static int ApiGetScoreTapeThread(void *data_raw)
+{
+  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  program.api_thread_count++;
+
+#if defined(PLATFORM_EMSCRIPTEN)
+  Emscripten_ApiGetScoreTape_HttpRequest(request, data_raw);
+#else
+  ApiGetScoreTape_HttpRequest(request, response, data_raw);
+#endif
+
+  program.api_thread_count--;
+
+  checked_free(request);
+  checked_free(response);
+
+  return 0;
+}
+
+void ApiGetScoreTapeAsThread(int nr, int id, char *score_tape_basename)
+{
+  struct ApiGetScoreTapeThreadData *data =
+    CreateThreadData_ApiGetScoreTape(nr, id, score_tape_basename);
+
+  ExecuteAsThread(ApiGetScoreTapeThread,
+                 "ApiGetScoreTape", data,
+                 "download score tape from server");
+}
+
+
+// ============================================================================
+// rename player API functions
+// ============================================================================
+
+struct ApiRenamePlayerThreadData
+{
+  char *player_name;
+  char *player_uuid;
+};
+
+static void *CreateThreadData_ApiRenamePlayer(void)
+{
+  struct ApiRenamePlayerThreadData *data =
+    checked_malloc(sizeof(struct ApiRenamePlayerThreadData));
+
+  data->player_name = getStringCopy(setup.player_name);
+  data->player_uuid = getStringCopy(setup.player_uuid);
+
+  return data;
+}
+
+static void FreeThreadData_ApiRenamePlayer(void *data_raw)
+{
+  struct ApiRenamePlayerThreadData *data = data_raw;
+
+  checked_free(data->player_name);
+  checked_free(data->player_uuid);
+  checked_free(data);
+}
+
+static boolean SetRequest_ApiRenamePlayer(struct HttpRequest *request,
+                                         void *data_raw)
+{
+  struct ApiRenamePlayerThreadData *data = data_raw;
+  char *player_name_raw = data->player_name;
+  char *player_uuid_raw = data->player_uuid;
+
+  request->hostname = setup.api_server_hostname;
+  request->port     = API_SERVER_PORT;
+  request->method   = API_SERVER_METHOD;
+  request->uri      = API_SERVER_URI_RENAME;
+
+  char *player_name = getEscapedJSON(player_name_raw);
+  char *player_uuid = getEscapedJSON(player_uuid_raw);
+
+  snprintf(request->body, MAX_HTTP_BODY_SIZE,
+          "{\n"
+          "%s"
+          "  \"game_version\":         \"%s\",\n"
+          "  \"game_platform\":        \"%s\",\n"
+          "  \"name\":                 \"%s\",\n"
+          "  \"uuid\":                 \"%s\"\n"
+          "}\n",
+          getPasswordJSON(setup.api_server_password),
+          getProgramRealVersionString(),
+          getProgramPlatformString(),
+          player_name,
+          player_uuid);
+
+  checked_free(player_name);
+  checked_free(player_uuid);
+
+  ConvertHttpRequestBodyToServerEncoding(request);
+
+  return TRUE;
+}
+
+static void HandleResponse_ApiRenamePlayer(struct HttpResponse *response,
+                                          void *data_raw)
+{
+  // nothing to do here
+}
+
+#if defined(PLATFORM_EMSCRIPTEN)
+static void Emscripten_ApiRenamePlayer_Loaded(unsigned handle, void *data_raw,
+                                             void *buffer, unsigned int size)
+{
+  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+
+  if (response != NULL)
+  {
+    HandleResponse_ApiRenamePlayer(response, data_raw);
+
+    checked_free(response);
+  }
+  else
+  {
+    Error("server response too large to handle (%d bytes)", size);
+  }
+
+  FreeThreadData_ApiRenamePlayer(data_raw);
+}
+
+static void Emscripten_ApiRenamePlayer_Failed(unsigned handle, void *data_raw,
+                                             int code, const char *status)
+{
+  Error("server failed to handle request: %d %s", code, status);
+
+  FreeThreadData_ApiRenamePlayer(data_raw);
+}
+
+static void Emscripten_ApiRenamePlayer_Progress(unsigned handle, void *data_raw,
+                                               int bytes, int size)
+{
+  // nothing to do here
+}
+
+static void Emscripten_ApiRenamePlayer_HttpRequest(struct HttpRequest *request,
+                                                  void *data_raw)
+{
+  if (!SetRequest_ApiRenamePlayer(request, data_raw))
+  {
+    FreeThreadData_ApiRenamePlayer(data_raw);
+
+    return;
+  }
+
+  emscripten_async_wget2_data(request->uri,
+                             request->method,
+                             request->body,
+                             data_raw,
+                             TRUE,
+                             Emscripten_ApiRenamePlayer_Loaded,
+                             Emscripten_ApiRenamePlayer_Failed,
+                             Emscripten_ApiRenamePlayer_Progress);
+}
+
+#else
+
+static void ApiRenamePlayer_HttpRequestExt(struct HttpRequest *request,
+                                          struct HttpResponse *response,
+                                          void *data_raw)
+{
+  if (!SetRequest_ApiRenamePlayer(request, data_raw))
+    return;
+
+  if (!DoHttpRequest(request, response))
+  {
+    Error("HTTP request failed: %s", GetHttpError());
+
+    return;
+  }
+
+  if (!HTTP_SUCCESS(response->status_code))
+  {
+    Error("server failed to handle request: %d %s",
+         response->status_code,
+         response->status_text);
+
+    return;
+  }
+
+  HandleResponse_ApiRenamePlayer(response, data_raw);
+}
+
+static void ApiRenamePlayer_HttpRequest(struct HttpRequest *request,
+                                   struct HttpResponse *response,
+                                   void *data_raw)
+{
+  ApiRenamePlayer_HttpRequestExt(request, response, data_raw);
+
+  FreeThreadData_ApiRenamePlayer(data_raw);
+}
+#endif
+
+static int ApiRenamePlayerThread(void *data_raw)
+{
+  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  program.api_thread_count++;
+
+#if defined(PLATFORM_EMSCRIPTEN)
+  Emscripten_ApiRenamePlayer_HttpRequest(request, data_raw);
+#else
+  ApiRenamePlayer_HttpRequest(request, response, data_raw);
+#endif
+
+  program.api_thread_count--;
+
+  checked_free(request);
+  checked_free(response);
+
+  return 0;
+}
+
+void ApiRenamePlayerAsThread(void)
+{
+  struct ApiRenamePlayerThreadData *data = CreateThreadData_ApiRenamePlayer();
+
+  ExecuteAsThread(ApiRenamePlayerThread,
+                 "ApiRenamePlayer", data,
+                 "rename player on server");
+}
+
+
+// ============================================================================
+// reset player UUID API functions
+// ============================================================================
+
+struct ApiResetUUIDThreadData
+{
+  char *player_name;
+  char *player_uuid_old;
+  char *player_uuid_new;
+};
+
+static void *CreateThreadData_ApiResetUUID(char *uuid_new)
+{
+  struct ApiResetUUIDThreadData *data =
+    checked_malloc(sizeof(struct ApiResetUUIDThreadData));
+
+  data->player_name     = getStringCopy(setup.player_name);
+  data->player_uuid_old = getStringCopy(setup.player_uuid);
+  data->player_uuid_new = getStringCopy(uuid_new);
+
+  return data;
+}
+
+static void FreeThreadData_ApiResetUUID(void *data_raw)
+{
+  struct ApiResetUUIDThreadData *data = data_raw;
+
+  checked_free(data->player_name);
+  checked_free(data->player_uuid_old);
+  checked_free(data->player_uuid_new);
+  checked_free(data);
+}
+
+static boolean SetRequest_ApiResetUUID(struct HttpRequest *request,
+                                      void *data_raw)
+{
+  struct ApiResetUUIDThreadData *data = data_raw;
+  char *player_name_raw = data->player_name;
+  char *player_uuid_old_raw = data->player_uuid_old;
+  char *player_uuid_new_raw = data->player_uuid_new;
+
+  request->hostname = setup.api_server_hostname;
+  request->port     = API_SERVER_PORT;
+  request->method   = API_SERVER_METHOD;
+  request->uri      = API_SERVER_URI_RESETUUID;
+
+  char *player_name = getEscapedJSON(player_name_raw);
+  char *player_uuid_old = getEscapedJSON(player_uuid_old_raw);
+  char *player_uuid_new = getEscapedJSON(player_uuid_new_raw);
+
+  snprintf(request->body, MAX_HTTP_BODY_SIZE,
+          "{\n"
+          "%s"
+          "  \"game_version\":         \"%s\",\n"
+          "  \"game_platform\":        \"%s\",\n"
+          "  \"name\":                 \"%s\",\n"
+          "  \"uuid_old\":             \"%s\",\n"
+          "  \"uuid_new\":             \"%s\"\n"
+          "}\n",
+          getPasswordJSON(setup.api_server_password),
+          getProgramRealVersionString(),
+          getProgramPlatformString(),
+          player_name,
+          player_uuid_old,
+          player_uuid_new);
+
+  checked_free(player_name);
+  checked_free(player_uuid_old);
+  checked_free(player_uuid_new);
+
+  ConvertHttpRequestBodyToServerEncoding(request);
+
+  return TRUE;
+}
+
+static void HandleResponse_ApiResetUUID(struct HttpResponse *response,
+                                       void *data_raw)
+{
+  struct ApiResetUUIDThreadData *data = data_raw;
+
+  // upgrade player UUID in server setup file
+  setup.player_uuid = getStringCopy(data->player_uuid_new);
+  setup.player_version = 2;
+
+  SaveSetup_ServerSetup();
+}
+
+#if defined(PLATFORM_EMSCRIPTEN)
+static void Emscripten_ApiResetUUID_Loaded(unsigned handle, void *data_raw,
+                                          void *buffer, unsigned int size)
+{
+  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+
+  if (response != NULL)
+  {
+    HandleResponse_ApiResetUUID(response, data_raw);
+
+    checked_free(response);
+  }
+  else
+  {
+    Error("server response too large to handle (%d bytes)", size);
+  }
+
+  FreeThreadData_ApiResetUUID(data_raw);
+}
+
+static void Emscripten_ApiResetUUID_Failed(unsigned handle, void *data_raw,
+                                          int code, const char *status)
+{
+  Error("server failed to handle request: %d %s", code, status);
+
+  FreeThreadData_ApiResetUUID(data_raw);
+}
+
+static void Emscripten_ApiResetUUID_Progress(unsigned handle, void *data_raw,
+                                            int bytes, int size)
+{
+  // nothing to do here
+}
+
+static void Emscripten_ApiResetUUID_HttpRequest(struct HttpRequest *request,
+                                               void *data_raw)
+{
+  if (!SetRequest_ApiResetUUID(request, data_raw))
+  {
+    FreeThreadData_ApiResetUUID(data_raw);
+
+    return;
+  }
+
+  emscripten_async_wget2_data(request->uri,
+                             request->method,
+                             request->body,
+                             data_raw,
+                             TRUE,
+                             Emscripten_ApiResetUUID_Loaded,
+                             Emscripten_ApiResetUUID_Failed,
+                             Emscripten_ApiResetUUID_Progress);
+}
+
+#else
+
+static void ApiResetUUID_HttpRequestExt(struct HttpRequest *request,
+                                       struct HttpResponse *response,
+                                       void *data_raw)
+{
+  if (!SetRequest_ApiResetUUID(request, data_raw))
+    return;
+
+  if (!DoHttpRequest(request, response))
+  {
+    Error("HTTP request failed: %s", GetHttpError());
+
+    return;
+  }
+
+  if (!HTTP_SUCCESS(response->status_code))
+  {
+    Error("server failed to handle request: %d %s",
+         response->status_code,
+         response->status_text);
+
+    return;
+  }
+
+  HandleResponse_ApiResetUUID(response, data_raw);
+}
+
+static void ApiResetUUID_HttpRequest(struct HttpRequest *request,
+                                    struct HttpResponse *response,
+                                    void *data_raw)
+{
+  ApiResetUUID_HttpRequestExt(request, response, data_raw);
+
+  FreeThreadData_ApiResetUUID(data_raw);
+}
+#endif
+
+static int ApiResetUUIDThread(void *data_raw)
+{
+  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
+  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+
+  program.api_thread_count++;
+
+#if defined(PLATFORM_EMSCRIPTEN)
+  Emscripten_ApiResetUUID_HttpRequest(request, data_raw);
+#else
+  ApiResetUUID_HttpRequest(request, response, data_raw);
+#endif
+
+  program.api_thread_count--;
+
+  checked_free(request);
+  checked_free(response);
+
+  return 0;
+}
+
+void ApiResetUUIDAsThread(char *uuid_new)
+{
+  struct ApiResetUUIDThreadData *data = CreateThreadData_ApiResetUUID(uuid_new);
+
+  ExecuteAsThread(ApiResetUUIDThread,
+                 "ApiResetUUID", data,
+                 "reset UUID on server");
+}
diff --git a/src/api.h b/src/api.h
new file mode 100644 (file)
index 0000000..4f89742
--- /dev/null
+++ b/src/api.h
@@ -0,0 +1,21 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2022 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// api.h
+// ============================================================================
+
+#ifndef API_H
+#define API_H
+
+void ApiAddScoreAsThread(int, boolean, char *);
+void ApiGetScoreAsThread(int);
+void ApiGetScoreTapeAsThread(int, int, char *);
+void ApiRenamePlayerAsThread(void);
+void ApiResetUUIDAsThread(char *);
+
+#endif
index 96d500c1fc1fe80ad203d112ed77b4d33254ac02..7262ac97ca94a3cdcd916cbb925593b6eacb42ce 100644 (file)
 
 struct ConfigTypeInfo image_config_suffix[] =
 {
-  { ".x",                              ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".y",                              ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".xpos",                           ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".ypos",                           ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".width",                          ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".height",                         ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".vertical",                       "false",        TYPE_BOOLEAN    },
-  { ".offset",                         ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".xoffset",                                ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".yoffset",                                ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".2nd_movement_tile",              "false",        TYPE_BOOLEAN    },
-  { ".2nd_vertical",                   ARG_UNDEFINED,  TYPE_BOOLEAN    },
-  { ".2nd_offset",                     ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".2nd_xoffset",                    ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".2nd_yoffset",                    ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".2nd_swap_tiles",                 ARG_UNDEFINED,  TYPE_BOOLEAN    },
-  { ".frames",                         ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".frames_per_line",                        ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".start_frame",                    ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".delay",                          "1",            TYPE_INTEGER    },
-  { ".anim_mode",                      ARG_UNDEFINED,  TYPE_STRING     },
-  { ".global_sync",                    "false",        TYPE_BOOLEAN    },
-  { ".crumbled_like",                  ARG_UNDEFINED,  TYPE_ELEMENT    },
-  { ".diggable_like",                  ARG_UNDEFINED,  TYPE_ELEMENT    },
-  { ".border_size",                    ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".step_offset",                    "4",            TYPE_INTEGER    },
-  { ".step_xoffset",                   ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".step_yoffset",                   ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".step_delay",                     "1",            TYPE_INTEGER    },
-  { ".direction",                      ARG_UNDEFINED,  TYPE_STRING     },
-  { ".position",                       ARG_UNDEFINED,  TYPE_STRING     },
-  { ".draw_xoffset",                   "0",            TYPE_INTEGER    },
-  { ".draw_yoffset",                   "0",            TYPE_INTEGER    },
-  { ".draw_masked",                    ARG_UNDEFINED,  TYPE_BOOLEAN    },
-  { ".draw_order",                     ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".init_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".init_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".init_delay_action",              ARG_UNDEFINED,  TYPE_STRING     },
-  { ".anim_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".anim_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".anim_delay_action",              ARG_UNDEFINED,  TYPE_STRING     },
-  { ".post_delay_fixed",               ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".post_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".post_delay_action",              ARG_UNDEFINED,  TYPE_STRING     },
-  { ".init_event",                     ARG_UNDEFINED,  TYPE_STRING     },
-  { ".init_event_action",              ARG_UNDEFINED,  TYPE_STRING     },
-  { ".anim_event",                     ARG_UNDEFINED,  TYPE_STRING     },
-  { ".anim_event_action",              ARG_UNDEFINED,  TYPE_STRING     },
-  { ".name",                           ARG_UNDEFINED,  TYPE_STRING     },
-  { ".scale_up_factor",                        ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".tile_size",                      ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".clone_from",                     ARG_UNDEFINED,  TYPE_GRAPHIC    },
-  { ".fade_mode",                      ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".fade_delay",                     ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".post_delay",                     ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".auto_delay",                     ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".auto_delay_unit",                        ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".align",                          ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".valign",                         ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".sort_priority",                  ARG_UNDEFINED,  TYPE_INTEGER    },
-  { ".class",                          ARG_UNDEFINED,  TYPE_STRING     },
-  { ".style",                          ARG_UNDEFINED,  TYPE_STRING     },
-  { ".active_xoffset",                 "0",            TYPE_INTEGER    },
-  { ".active_yoffset",                 "0",            TYPE_INTEGER    },
-  { ".pressed_xoffset",                        "0",            TYPE_INTEGER    },
-  { ".pressed_yoffset",                        "0",            TYPE_INTEGER    },
-
-  { NULL,                              NULL,           0               }
+  { ".x",                                      ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".y",                                      ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".xpos",                                   ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".ypos",                                   ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".width",                                  ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".height",                                 ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".vertical",                               "false",        TYPE_BOOLEAN            },
+  { ".offset",                                 ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".xoffset",                                        ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".yoffset",                                        ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".2nd_movement_tile",                      "false",        TYPE_BOOLEAN            },
+  { ".2nd_vertical",                           ARG_UNDEFINED,  TYPE_BOOLEAN            },
+  { ".2nd_offset",                             ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".2nd_xoffset",                            ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".2nd_yoffset",                            ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".2nd_swap_tiles",                         ARG_UNDEFINED,  TYPE_BOOLEAN            },
+  { ".frames",                                 ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".frames_per_line",                                ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".start_frame",                            ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".delay",                                  "1",            TYPE_INTEGER            },
+  { ".anim_mode",                              ARG_UNDEFINED,  TYPE_STRING             },
+  { ".global_sync",                            "false",        TYPE_BOOLEAN            },
+  { ".global_anim_sync",                       "false",        TYPE_BOOLEAN            },
+  { ".crumbled_like",                          ARG_UNDEFINED,  TYPE_ELEMENT            },
+  { ".diggable_like",                          ARG_UNDEFINED,  TYPE_ELEMENT            },
+  { ".border_size",                            ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".step_offset",                            "4",            TYPE_INTEGER            },
+  { ".step_xoffset",                           ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".step_yoffset",                           ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".step_delay",                             "1",            TYPE_INTEGER            },
+  { ".direction",                              ARG_UNDEFINED,  TYPE_STRING             },
+  { ".position",                               ARG_UNDEFINED,  TYPE_STRING             },
+  { ".draw_xoffset",                           "0",            TYPE_INTEGER            },
+  { ".draw_yoffset",                           "0",            TYPE_INTEGER            },
+  { ".draw_masked",                            ARG_UNDEFINED,  TYPE_BOOLEAN            },
+  { ".draw_order",                             ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".init_delay_fixed",                       ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".init_delay_random",                      ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".init_delay_action",                      ARG_UNDEFINED,  TYPE_STRING             },
+  { ".anim_delay_fixed",                       ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".anim_delay_random",                      ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".anim_delay_action",                      ARG_UNDEFINED,  TYPE_STRING             },
+  { ".post_delay_fixed",                       ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".post_delay_random",                      ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".post_delay_action",                      ARG_UNDEFINED,  TYPE_STRING             },
+  { ".init_event",                             ARG_UNDEFINED,  TYPE_STRING             },
+  { ".init_event_action",                      ARG_UNDEFINED,  TYPE_STRING             },
+  { ".anim_event",                             ARG_UNDEFINED,  TYPE_STRING             },
+  { ".anim_event_action",                      ARG_UNDEFINED,  TYPE_STRING             },
+  { ".name",                                   ARG_UNDEFINED,  TYPE_STRING             },
+  { ".scale_up_factor",                                ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".tile_size",                              ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".clone_from",                             ARG_UNDEFINED,  TYPE_GRAPHIC            },
+  { ".fade_mode",                              ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".fade_delay",                             ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".post_delay",                             ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".auto_delay",                             ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".auto_delay_unit",                                ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".align",                                  ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".valign",                                 ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".sort_priority",                          ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".class",                                  ARG_UNDEFINED,  TYPE_STRING             },
+  { ".style",                                  ARG_UNDEFINED,  TYPE_STRING             },
+  { ".alpha",                                  ARG_UNDEFINED,  TYPE_INTEGER            },
+  { ".active_xoffset",                         "0",            TYPE_INTEGER            },
+  { ".active_yoffset",                         "0",            TYPE_INTEGER            },
+  { ".pressed_xoffset",                                "0",            TYPE_INTEGER            },
+  { ".pressed_yoffset",                                "0",            TYPE_INTEGER            },
+  { ".stacked_xfactor",                                "1",            TYPE_INTEGER            },
+  { ".stacked_yfactor",                                "1",            TYPE_INTEGER            },
+  { ".stacked_xoffset",                                "0",            TYPE_INTEGER            },
+  { ".stacked_yoffset",                                "0",            TYPE_INTEGER            },
+
+  { NULL,                                      NULL,           0                       }
 };
 
 struct ConfigInfo image_config[] =
@@ -97,5704 +103,6829 @@ struct ConfigInfo image_config[] =
 
   // images for Boulder Dash style elements and actions
 
-  { "bd_wall",                                 "RocksDC.png"           },
-  { "bd_wall.xpos",                            "12"                    },
-  { "bd_wall.ypos",                            "9"                     },
-  { "bd_wall.frames",                          "1"                     },
-  { "bd_wall.EDITOR",                          "RocksDC.png"           },
-  { "bd_wall.EDITOR.xpos",                     "14"                    },
-  { "bd_wall.EDITOR.ypos",                     "13"                    },
-
-  { "bd_rock",                                 "RocksDC.png"           },
-  { "bd_rock.xpos",                            "12"                    },
-  { "bd_rock.ypos",                            "10"                    },
-  { "bd_rock.frames",                          "1"                     },
-  { "bd_rock.EDITOR",                          "RocksDC.png"           },
-  { "bd_rock.EDITOR.xpos",                     "14"                    },
-  { "bd_rock.EDITOR.ypos",                     "14"                    },
-  { "bd_rock.moving.left",                     "RocksDC.png"           },
-  { "bd_rock.moving.left.xpos",                        "12"                    },
-  { "bd_rock.moving.left.ypos",                        "10"                    },
-  { "bd_rock.moving.left.frames",              "4"                     },
-  { "bd_rock.moving.left.delay",               "2"                     },
-  { "bd_rock.moving.left.anim_mode",           "reverse"               },
-  { "bd_rock.moving.right",                    "RocksDC.png"           },
-  { "bd_rock.moving.right.xpos",               "12"                    },
-  { "bd_rock.moving.right.ypos",               "10"                    },
-  { "bd_rock.moving.right.frames",             "4"                     },
-  { "bd_rock.moving.right.start_frame",                "1"                     },
-  { "bd_rock.moving.right.delay",              "2"                     },
-  { "bd_rock.pushing.left",                    "RocksDC.png"           },
-  { "bd_rock.pushing.left.xpos",               "12"                    },
-  { "bd_rock.pushing.left.ypos",               "10"                    },
-  { "bd_rock.pushing.left.frames",             "4"                     },
-  { "bd_rock.pushing.left.delay",              "2"                     },
-  { "bd_rock.pushing.left.anim_mode",          "reverse"               },
-  { "bd_rock.pushing.right",                   "RocksDC.png"           },
-  { "bd_rock.pushing.right.xpos",              "12"                    },
-  { "bd_rock.pushing.right.ypos",              "10"                    },
-  { "bd_rock.pushing.right.frames",            "4"                     },
-  { "bd_rock.pushing.right.start_frame",       "1"                     },
-  { "bd_rock.pushing.right.delay",             "2"                     },
-
-  { "bd_diamond",                              "RocksElements.png"     },
-  { "bd_diamond.xpos",                         "0"                     },
-  { "bd_diamond.ypos",                         "10"                    },
-  { "bd_diamond.frames",                       "4"                     },
-  { "bd_diamond.delay",                                "4"                     },
-  { "bd_diamond.anim_mode",                    "reverse"               },
-  { "bd_diamond.moving",                       "RocksElements.png"     },
-  { "bd_diamond.moving.xpos",                  "3"                     },
-  { "bd_diamond.moving.ypos",                  "10"                    },
-  { "bd_diamond.moving.frames",                        "2"                     },
-  { "bd_diamond.moving.delay",                 "4"                     },
-  { "bd_diamond.falling",                      "RocksElements.png"     },
-  { "bd_diamond.falling.xpos",                 "3"                     },
-  { "bd_diamond.falling.ypos",                 "10"                    },
-  { "bd_diamond.falling.frames",               "2"                     },
-  { "bd_diamond.falling.delay",                        "4"                     },
-  { "bd_diamond.collecting",                   "RocksCollect.png"      },
-  { "bd_diamond.collecting.xpos",              "0"                     },
-  { "bd_diamond.collecting.ypos",              "8"                     },
-  { "bd_diamond.collecting.frames",            "7"                     },
-  { "bd_diamond.collecting.anim_mode",         "linear"                },
-
-  { "bd_magic_wall",                           "RocksElements.png"     },
-  { "bd_magic_wall.xpos",                      "12"                    },
-  { "bd_magic_wall.ypos",                      "10"                    },
-  { "bd_magic_wall.frames",                    "1"                     },
-  { "bd_magic_wall.active",                    "RocksElements.png"     },
-  { "bd_magic_wall.active.xpos",               "12"                    },
-  { "bd_magic_wall.active.ypos",               "10"                    },
-  { "bd_magic_wall.active.frames",             "4"                     },
-  { "bd_magic_wall.active.anim_mode",          "reverse"               },
-  { "bd_magic_wall.active.delay",              "4"                     },
-  { "bd_magic_wall.active.global_sync",                "true"                  },
-  { "bd_magic_wall.filling",                   "RocksElements.png"     },
-  { "bd_magic_wall.filling.xpos",              "12"                    },
-  { "bd_magic_wall.filling.ypos",              "10"                    },
-  { "bd_magic_wall.filling.frames",            "4"                     },
-  { "bd_magic_wall.filling.anim_mode",         "reverse"               },
-  { "bd_magic_wall.filling.delay",             "4"                     },
-  { "bd_magic_wall.filling.global_sync",       "true"                  },
-  { "bd_magic_wall_full",                      "RocksElements.png"     },
-  { "bd_magic_wall_full.xpos",                 "12"                    },
-  { "bd_magic_wall_full.ypos",                 "10"                    },
-  { "bd_magic_wall_full.frames",               "4"                     },
-  { "bd_magic_wall_full.anim_mode",            "reverse"               },
-  { "bd_magic_wall_full.delay",                        "4"                     },
-  { "bd_magic_wall_full.global_sync",          "true"                  },
-  { "bd_magic_wall.emptying",                  "RocksElements.png"     },
-  { "bd_magic_wall.emptying.xpos",             "12"                    },
-  { "bd_magic_wall.emptying.ypos",             "10"                    },
-  { "bd_magic_wall.emptying.frames",           "4"                     },
-  { "bd_magic_wall.emptying.anim_mode",                "reverse"               },
-  { "bd_magic_wall.emptying.delay",            "4"                     },
-  { "bd_magic_wall.emptying.global_sync",      "true"                  },
-  { "bd_magic_wall_dead",                      "RocksElements.png"     },
-  { "bd_magic_wall_dead.xpos",                 "12"                    },
-  { "bd_magic_wall_dead.ypos",                 "10"                    },
-  { "bd_magic_wall_dead.frames",               "1"                     },
-
-  { "bd_amoeba",                               "RocksElements.png"     },
-  { "bd_amoeba.xpos",                          "8"                     },
-  { "bd_amoeba.ypos",                          "6"                     },
-  { "bd_amoeba.frames",                                "4"                     },
-  { "bd_amoeba.delay",                         "1000000"               },
-  { "bd_amoeba.anim_mode",                     "random"                },
-  { "bd_amoeba.EDITOR",                                "RocksElements.png"     },
-  { "bd_amoeba.EDITOR.xpos",                   "8"                     },
-  { "bd_amoeba.EDITOR.ypos",                   "7"                     },
-
-  { "bd_butterfly",                            "RocksElements.png"     },
-  { "bd_butterfly.xpos",                       "4"                     },
-  { "bd_butterfly.ypos",                       "12"                    },
-  { "bd_butterfly.frames",                     "2"                     },
-  { "bd_butterfly.anim_mode",                  "pingpong"              },
-  { "bd_butterfly.delay",                      "4"                     },
-  { "bd_butterfly.global_sync",                        "true"                  },
-  { "bd_butterfly.right",                      "RocksElements.png"     },
-  { "bd_butterfly.right.xpos",                 "4"                     },
-  { "bd_butterfly.right.ypos",                 "12"                    },
-  { "bd_butterfly.right.frames",               "2"                     },
-  { "bd_butterfly.right.anim_mode",            "pingpong"              },
-  { "bd_butterfly.right.delay",                        "4"                     },
-  { "bd_butterfly.right.global_sync",          "true"                  },
-  { "bd_butterfly.right.EDITOR",               "RocksElements.png"     },
-  { "bd_butterfly.right.EDITOR.xpos",          "8"                     },
-  { "bd_butterfly.right.EDITOR.ypos",          "12"                    },
-  { "bd_butterfly.up",                         "RocksElements.png"     },
-  { "bd_butterfly.up.xpos",                    "4"                     },
-  { "bd_butterfly.up.ypos",                    "12"                    },
-  { "bd_butterfly.up.frames",                  "2"                     },
-  { "bd_butterfly.up.anim_mode",               "pingpong"              },
-  { "bd_butterfly.up.delay",                   "4"                     },
-  { "bd_butterfly.up.global_sync",             "true"                  },
-  { "bd_butterfly.up.EDITOR",                  "RocksElements.png"     },
-  { "bd_butterfly.up.EDITOR.xpos",             "9"                     },
-  { "bd_butterfly.up.EDITOR.ypos",             "12"                    },
-  { "bd_butterfly.left",                       "RocksElements.png"     },
-  { "bd_butterfly.left.xpos",                  "4"                     },
-  { "bd_butterfly.left.ypos",                  "12"                    },
-  { "bd_butterfly.left.frames",                        "2"                     },
-  { "bd_butterfly.left.anim_mode",             "pingpong"              },
-  { "bd_butterfly.left.delay",                 "4"                     },
-  { "bd_butterfly.left.global_sync",           "true"                  },
-  { "bd_butterfly.left.EDITOR",                        "RocksElements.png"     },
-  { "bd_butterfly.left.EDITOR.xpos",           "10"                    },
-  { "bd_butterfly.left.EDITOR.ypos",           "12"                    },
-  { "bd_butterfly.down",                       "RocksElements.png"     },
-  { "bd_butterfly.down.xpos",                  "4"                     },
-  { "bd_butterfly.down.ypos",                  "12"                    },
-  { "bd_butterfly.down.frames",                        "2"                     },
-  { "bd_butterfly.down.anim_mode",             "pingpong"              },
-  { "bd_butterfly.down.delay",                 "4"                     },
-  { "bd_butterfly.down.global_sync",           "true"                  },
-  { "bd_butterfly.down.EDITOR",                        "RocksElements.png"     },
-  { "bd_butterfly.down.EDITOR.xpos",           "11"                    },
-  { "bd_butterfly.down.EDITOR.ypos",           "12"                    },
-
-  { "bd_firefly",                              "RocksElements.png"     },
-  { "bd_firefly.xpos",                         "6"                     },
-  { "bd_firefly.ypos",                         "12"                    },
-  { "bd_firefly.frames",                       "2"                     },
-  { "bd_firefly.anim_mode",                    "pingpong"              },
-  { "bd_firefly.delay",                                "4"                     },
-  { "bd_firefly.global_sync",                  "true"                  },
-  { "bd_firefly.right",                                "RocksElements.png"     },
-  { "bd_firefly.right.xpos",                   "6"                     },
-  { "bd_firefly.right.ypos",                   "12"                    },
-  { "bd_firefly.right.frames",                 "2"                     },
-  { "bd_firefly.right.anim_mode",              "pingpong"              },
-  { "bd_firefly.right.delay",                  "4"                     },
-  { "bd_firefly.right.global_sync",            "true"                  },
-  { "bd_firefly.right.EDITOR",                 "RocksElements.png"     },
-  { "bd_firefly.right.EDITOR.xpos",            "12"                    },
-  { "bd_firefly.right.EDITOR.ypos",            "12"                    },
-  { "bd_firefly.up",                           "RocksElements.png"     },
-  { "bd_firefly.up.xpos",                      "6"                     },
-  { "bd_firefly.up.ypos",                      "12"                    },
-  { "bd_firefly.up.frames",                    "2"                     },
-  { "bd_firefly.up.anim_mode",                 "pingpong"              },
-  { "bd_firefly.up.delay",                     "4"                     },
-  { "bd_firefly.up.global_sync",               "true"                  },
-  { "bd_firefly.up.EDITOR",                    "RocksElements.png"     },
-  { "bd_firefly.up.EDITOR.xpos",               "13"                    },
-  { "bd_firefly.up.EDITOR.ypos",               "12"                    },
-  { "bd_firefly.left",                         "RocksElements.png"     },
-  { "bd_firefly.left.xpos",                    "6"                     },
-  { "bd_firefly.left.ypos",                    "12"                    },
-  { "bd_firefly.left.frames",                  "2"                     },
-  { "bd_firefly.left.anim_mode",               "pingpong"              },
-  { "bd_firefly.left.delay",                   "4"                     },
-  { "bd_firefly.left.global_sync",             "true"                  },
-  { "bd_firefly.left.EDITOR",                  "RocksElements.png"     },
-  { "bd_firefly.left.EDITOR.xpos",             "14"                    },
-  { "bd_firefly.left.EDITOR.ypos",             "12"                    },
-  { "bd_firefly.down",                         "RocksElements.png"     },
-  { "bd_firefly.down.xpos",                    "6"                     },
-  { "bd_firefly.down.ypos",                    "12"                    },
-  { "bd_firefly.down.frames",                  "2"                     },
-  { "bd_firefly.down.anim_mode",               "pingpong"              },
-  { "bd_firefly.down.delay",                   "4"                     },
-  { "bd_firefly.down.global_sync",             "true"                  },
-  { "bd_firefly.down.EDITOR",                  "RocksElements.png"     },
-  { "bd_firefly.down.EDITOR.xpos",             "15"                    },
-  { "bd_firefly.down.EDITOR.ypos",             "12"                    },
+  { "bd_wall",                                         "RocksDC.png"                   },
+  { "bd_wall.xpos",                                    "12"                            },
+  { "bd_wall.ypos",                                    "9"                             },
+  { "bd_wall.frames",                                  "1"                             },
+  { "bd_wall.EDITOR",                                  "RocksDC.png"                   },
+  { "bd_wall.EDITOR.xpos",                             "14"                            },
+  { "bd_wall.EDITOR.ypos",                             "13"                            },
+
+  { "bd_rock",                                         "RocksDC.png"                   },
+  { "bd_rock.xpos",                                    "12"                            },
+  { "bd_rock.ypos",                                    "10"                            },
+  { "bd_rock.frames",                                  "1"                             },
+  { "bd_rock.EDITOR",                                  "RocksDC.png"                   },
+  { "bd_rock.EDITOR.xpos",                             "14"                            },
+  { "bd_rock.EDITOR.ypos",                             "14"                            },
+  { "bd_rock.moving.left",                             "RocksDC.png"                   },
+  { "bd_rock.moving.left.xpos",                                "12"                            },
+  { "bd_rock.moving.left.ypos",                                "10"                            },
+  { "bd_rock.moving.left.frames",                      "4"                             },
+  { "bd_rock.moving.left.delay",                       "2"                             },
+  { "bd_rock.moving.left.anim_mode",                   "reverse"                       },
+  { "bd_rock.moving.right",                            "RocksDC.png"                   },
+  { "bd_rock.moving.right.xpos",                       "12"                            },
+  { "bd_rock.moving.right.ypos",                       "10"                            },
+  { "bd_rock.moving.right.frames",                     "4"                             },
+  { "bd_rock.moving.right.start_frame",                        "1"                             },
+  { "bd_rock.moving.right.delay",                      "2"                             },
+  { "bd_rock.pushing.left",                            "RocksDC.png"                   },
+  { "bd_rock.pushing.left.xpos",                       "12"                            },
+  { "bd_rock.pushing.left.ypos",                       "10"                            },
+  { "bd_rock.pushing.left.frames",                     "4"                             },
+  { "bd_rock.pushing.left.delay",                      "2"                             },
+  { "bd_rock.pushing.left.anim_mode",                  "reverse"                       },
+  { "bd_rock.pushing.right",                           "RocksDC.png"                   },
+  { "bd_rock.pushing.right.xpos",                      "12"                            },
+  { "bd_rock.pushing.right.ypos",                      "10"                            },
+  { "bd_rock.pushing.right.frames",                    "4"                             },
+  { "bd_rock.pushing.right.start_frame",               "1"                             },
+  { "bd_rock.pushing.right.delay",                     "2"                             },
+
+  { "bd_diamond",                                      "RocksElements.png"             },
+  { "bd_diamond.xpos",                                 "0"                             },
+  { "bd_diamond.ypos",                                 "10"                            },
+  { "bd_diamond.frames",                               "4"                             },
+  { "bd_diamond.delay",                                        "4"                             },
+  { "bd_diamond.anim_mode",                            "reverse"                       },
+  { "bd_diamond.moving",                               "RocksElements.png"             },
+  { "bd_diamond.moving.xpos",                          "3"                             },
+  { "bd_diamond.moving.ypos",                          "10"                            },
+  { "bd_diamond.moving.frames",                                "2"                             },
+  { "bd_diamond.moving.delay",                         "4"                             },
+  { "bd_diamond.falling",                              "RocksElements.png"             },
+  { "bd_diamond.falling.xpos",                         "3"                             },
+  { "bd_diamond.falling.ypos",                         "10"                            },
+  { "bd_diamond.falling.frames",                       "2"                             },
+  { "bd_diamond.falling.delay",                                "4"                             },
+  { "bd_diamond.collecting",                           "RocksCollect.png"              },
+  { "bd_diamond.collecting.xpos",                      "0"                             },
+  { "bd_diamond.collecting.ypos",                      "8"                             },
+  { "bd_diamond.collecting.frames",                    "7"                             },
+  { "bd_diamond.collecting.anim_mode",                 "linear"                        },
+
+  { "bd_magic_wall",                                   "RocksElements.png"             },
+  { "bd_magic_wall.xpos",                              "12"                            },
+  { "bd_magic_wall.ypos",                              "10"                            },
+  { "bd_magic_wall.frames",                            "1"                             },
+  { "bd_magic_wall.active",                            "RocksElements.png"             },
+  { "bd_magic_wall.active.xpos",                       "12"                            },
+  { "bd_magic_wall.active.ypos",                       "10"                            },
+  { "bd_magic_wall.active.frames",                     "4"                             },
+  { "bd_magic_wall.active.anim_mode",                  "reverse"                       },
+  { "bd_magic_wall.active.delay",                      "4"                             },
+  { "bd_magic_wall.active.global_sync",                        "true"                          },
+  { "bd_magic_wall.filling",                           "RocksElements.png"             },
+  { "bd_magic_wall.filling.xpos",                      "12"                            },
+  { "bd_magic_wall.filling.ypos",                      "10"                            },
+  { "bd_magic_wall.filling.frames",                    "4"                             },
+  { "bd_magic_wall.filling.anim_mode",                 "reverse"                       },
+  { "bd_magic_wall.filling.delay",                     "4"                             },
+  { "bd_magic_wall.filling.global_sync",               "true"                          },
+  { "bd_magic_wall_full",                              "RocksElements.png"             },
+  { "bd_magic_wall_full.xpos",                         "12"                            },
+  { "bd_magic_wall_full.ypos",                         "10"                            },
+  { "bd_magic_wall_full.frames",                       "4"                             },
+  { "bd_magic_wall_full.anim_mode",                    "reverse"                       },
+  { "bd_magic_wall_full.delay",                                "4"                             },
+  { "bd_magic_wall_full.global_sync",                  "true"                          },
+  { "bd_magic_wall.emptying",                          "RocksElements.png"             },
+  { "bd_magic_wall.emptying.xpos",                     "12"                            },
+  { "bd_magic_wall.emptying.ypos",                     "10"                            },
+  { "bd_magic_wall.emptying.frames",                   "4"                             },
+  { "bd_magic_wall.emptying.anim_mode",                        "reverse"                       },
+  { "bd_magic_wall.emptying.delay",                    "4"                             },
+  { "bd_magic_wall.emptying.global_sync",              "true"                          },
+  { "bd_magic_wall_dead",                              "RocksElements.png"             },
+  { "bd_magic_wall_dead.xpos",                         "12"                            },
+  { "bd_magic_wall_dead.ypos",                         "10"                            },
+  { "bd_magic_wall_dead.frames",                       "1"                             },
+
+  { "bd_amoeba",                                       "RocksElements.png"             },
+  { "bd_amoeba.xpos",                                  "8"                             },
+  { "bd_amoeba.ypos",                                  "6"                             },
+  { "bd_amoeba.frames",                                        "4"                             },
+  { "bd_amoeba.anim_mode",                             "random_static"                 },
+  { "bd_amoeba.EDITOR",                                        "RocksElements.png"             },
+  { "bd_amoeba.EDITOR.xpos",                           "8"                             },
+  { "bd_amoeba.EDITOR.ypos",                           "7"                             },
+
+  { "bd_butterfly",                                    "RocksElements.png"             },
+  { "bd_butterfly.xpos",                               "4"                             },
+  { "bd_butterfly.ypos",                               "12"                            },
+  { "bd_butterfly.frames",                             "2"                             },
+  { "bd_butterfly.anim_mode",                          "pingpong"                      },
+  { "bd_butterfly.delay",                              "4"                             },
+  { "bd_butterfly.global_sync",                                "true"                          },
+  { "bd_butterfly.right",                              "RocksElements.png"             },
+  { "bd_butterfly.right.xpos",                         "4"                             },
+  { "bd_butterfly.right.ypos",                         "12"                            },
+  { "bd_butterfly.right.frames",                       "2"                             },
+  { "bd_butterfly.right.anim_mode",                    "pingpong"                      },
+  { "bd_butterfly.right.delay",                                "4"                             },
+  { "bd_butterfly.right.global_sync",                  "true"                          },
+  { "bd_butterfly.right.EDITOR",                       "RocksElements.png"             },
+  { "bd_butterfly.right.EDITOR.xpos",                  "8"                             },
+  { "bd_butterfly.right.EDITOR.ypos",                  "12"                            },
+  { "bd_butterfly.up",                                 "RocksElements.png"             },
+  { "bd_butterfly.up.xpos",                            "4"                             },
+  { "bd_butterfly.up.ypos",                            "12"                            },
+  { "bd_butterfly.up.frames",                          "2"                             },
+  { "bd_butterfly.up.anim_mode",                       "pingpong"                      },
+  { "bd_butterfly.up.delay",                           "4"                             },
+  { "bd_butterfly.up.global_sync",                     "true"                          },
+  { "bd_butterfly.up.EDITOR",                          "RocksElements.png"             },
+  { "bd_butterfly.up.EDITOR.xpos",                     "9"                             },
+  { "bd_butterfly.up.EDITOR.ypos",                     "12"                            },
+  { "bd_butterfly.left",                               "RocksElements.png"             },
+  { "bd_butterfly.left.xpos",                          "4"                             },
+  { "bd_butterfly.left.ypos",                          "12"                            },
+  { "bd_butterfly.left.frames",                                "2"                             },
+  { "bd_butterfly.left.anim_mode",                     "pingpong"                      },
+  { "bd_butterfly.left.delay",                         "4"                             },
+  { "bd_butterfly.left.global_sync",                   "true"                          },
+  { "bd_butterfly.left.EDITOR",                                "RocksElements.png"             },
+  { "bd_butterfly.left.EDITOR.xpos",                   "10"                            },
+  { "bd_butterfly.left.EDITOR.ypos",                   "12"                            },
+  { "bd_butterfly.down",                               "RocksElements.png"             },
+  { "bd_butterfly.down.xpos",                          "4"                             },
+  { "bd_butterfly.down.ypos",                          "12"                            },
+  { "bd_butterfly.down.frames",                                "2"                             },
+  { "bd_butterfly.down.anim_mode",                     "pingpong"                      },
+  { "bd_butterfly.down.delay",                         "4"                             },
+  { "bd_butterfly.down.global_sync",                   "true"                          },
+  { "bd_butterfly.down.EDITOR",                                "RocksElements.png"             },
+  { "bd_butterfly.down.EDITOR.xpos",                   "11"                            },
+  { "bd_butterfly.down.EDITOR.ypos",                   "12"                            },
+
+  { "bd_firefly",                                      "RocksElements.png"             },
+  { "bd_firefly.xpos",                                 "6"                             },
+  { "bd_firefly.ypos",                                 "12"                            },
+  { "bd_firefly.frames",                               "2"                             },
+  { "bd_firefly.anim_mode",                            "pingpong"                      },
+  { "bd_firefly.delay",                                        "4"                             },
+  { "bd_firefly.global_sync",                          "true"                          },
+  { "bd_firefly.right",                                        "RocksElements.png"             },
+  { "bd_firefly.right.xpos",                           "6"                             },
+  { "bd_firefly.right.ypos",                           "12"                            },
+  { "bd_firefly.right.frames",                         "2"                             },
+  { "bd_firefly.right.anim_mode",                      "pingpong"                      },
+  { "bd_firefly.right.delay",                          "4"                             },
+  { "bd_firefly.right.global_sync",                    "true"                          },
+  { "bd_firefly.right.EDITOR",                         "RocksElements.png"             },
+  { "bd_firefly.right.EDITOR.xpos",                    "12"                            },
+  { "bd_firefly.right.EDITOR.ypos",                    "12"                            },
+  { "bd_firefly.up",                                   "RocksElements.png"             },
+  { "bd_firefly.up.xpos",                              "6"                             },
+  { "bd_firefly.up.ypos",                              "12"                            },
+  { "bd_firefly.up.frames",                            "2"                             },
+  { "bd_firefly.up.anim_mode",                         "pingpong"                      },
+  { "bd_firefly.up.delay",                             "4"                             },
+  { "bd_firefly.up.global_sync",                       "true"                          },
+  { "bd_firefly.up.EDITOR",                            "RocksElements.png"             },
+  { "bd_firefly.up.EDITOR.xpos",                       "13"                            },
+  { "bd_firefly.up.EDITOR.ypos",                       "12"                            },
+  { "bd_firefly.left",                                 "RocksElements.png"             },
+  { "bd_firefly.left.xpos",                            "6"                             },
+  { "bd_firefly.left.ypos",                            "12"                            },
+  { "bd_firefly.left.frames",                          "2"                             },
+  { "bd_firefly.left.anim_mode",                       "pingpong"                      },
+  { "bd_firefly.left.delay",                           "4"                             },
+  { "bd_firefly.left.global_sync",                     "true"                          },
+  { "bd_firefly.left.EDITOR",                          "RocksElements.png"             },
+  { "bd_firefly.left.EDITOR.xpos",                     "14"                            },
+  { "bd_firefly.left.EDITOR.ypos",                     "12"                            },
+  { "bd_firefly.down",                                 "RocksElements.png"             },
+  { "bd_firefly.down.xpos",                            "6"                             },
+  { "bd_firefly.down.ypos",                            "12"                            },
+  { "bd_firefly.down.frames",                          "2"                             },
+  { "bd_firefly.down.anim_mode",                       "pingpong"                      },
+  { "bd_firefly.down.delay",                           "4"                             },
+  { "bd_firefly.down.global_sync",                     "true"                          },
+  { "bd_firefly.down.EDITOR",                          "RocksElements.png"             },
+  { "bd_firefly.down.EDITOR.xpos",                     "15"                            },
+  { "bd_firefly.down.EDITOR.ypos",                     "12"                            },
+
+  { "bd_expandable_wall",                              "RocksElements.png"             },
+  { "bd_expandable_wall.xpos",                         "5"                             },
+  { "bd_expandable_wall.ypos",                         "9"                             },
+  { "bd_expandable_wall.frames",                       "1"                             },
+  { "bd_expandable_wall.EDITOR",                       "RocksDC.png"                   },
+  { "bd_expandable_wall.EDITOR.xpos",                  "15"                            },
+  { "bd_expandable_wall.EDITOR.ypos",                  "15"                            },
+
+  // images for Boulder Dash style elements and actions (native game engine)
+
+  { "[bdx_default].exploding",                         "RocksElements.png"             },
+  { "[bdx_default].exploding.xpos",                    "0"                             },
+  { "[bdx_default].exploding.ypos",                    "4"                             },
+  { "[bdx_default].exploding.frames",                  "8"                             },
+  { "[bdx_default].exploding.delay",                   "5"                             },
+  { "[bdx_default].exploding.anim_mode",               "linear"                        },
+
+  { "[bdx_default].growing",                           "RocksElements.png"             },
+  { "[bdx_default].growing.xpos",                      "0"                             },
+  { "[bdx_default].growing.ypos",                      "4"                             },
+  { "[bdx_default].growing.frames",                    "8"                             },
+  { "[bdx_default].growing.delay",                     "4"                             },
+  { "[bdx_default].growing.anim_mode",                 "linear"                        },
+
+  { "bdx_player",                                      UNDEFINED_FILENAME              },
+  { "bdx_player.clone_from",                           "player_1"                      },
+  { "bdx_player.down",                                 UNDEFINED_FILENAME              },
+  { "bdx_player.down.clone_from",                      "player_1.down"                 },
+  { "bdx_player.up",                                   UNDEFINED_FILENAME              },
+  { "bdx_player.up.clone_from",                                "player_1.up"                   },
+  { "bdx_player.left",                                 UNDEFINED_FILENAME              },
+  { "bdx_player.left.clone_from",                      "player_1.left"                 },
+  { "bdx_player.right",                                        UNDEFINED_FILENAME              },
+  { "bdx_player.right.clone_from",                     "player_1.right"                },
+  { "bdx_player.moving.down",                          UNDEFINED_FILENAME              },
+  { "bdx_player.moving.down.clone_from",               "player_1.moving.down"          },
+  { "bdx_player.moving.up",                            UNDEFINED_FILENAME              },
+  { "bdx_player.moving.up.clone_from",                 "player_1.moving.up"            },
+  { "bdx_player.moving.left",                          UNDEFINED_FILENAME              },
+  { "bdx_player.moving.left.clone_from",               "player_1.moving.left"          },
+  { "bdx_player.moving.right",                         UNDEFINED_FILENAME              },
+  { "bdx_player.moving.right.clone_from",              "player_1.moving.right"         },
+  { "bdx_player.digging.down",                         UNDEFINED_FILENAME              },
+  { "bdx_player.digging.down.clone_from",              "player_1.digging.down"         },
+  { "bdx_player.digging.up",                           UNDEFINED_FILENAME              },
+  { "bdx_player.digging.up.clone_from",                        "player_1.digging.up"           },
+  { "bdx_player.digging.left",                         UNDEFINED_FILENAME              },
+  { "bdx_player.digging.left.clone_from",              "player_1.digging.left"         },
+  { "bdx_player.digging.right",                                UNDEFINED_FILENAME              },
+  { "bdx_player.digging.right.clone_from",             "player_1.digging.right"        },
+  { "bdx_player.collecting.down",                      UNDEFINED_FILENAME              },
+  { "bdx_player.collecting.down.clone_from",           "player_1.collecting.down"      },
+  { "bdx_player.collecting.up",                                UNDEFINED_FILENAME              },
+  { "bdx_player.collecting.up.clone_from",             "player_1.collecting.up"        },
+  { "bdx_player.collecting.left",                      UNDEFINED_FILENAME              },
+  { "bdx_player.collecting.left.clone_from",           "player_1.collecting.left"      },
+  { "bdx_player.collecting.right",                     UNDEFINED_FILENAME              },
+  { "bdx_player.collecting.right.clone_from",          "player_1.collecting.right"     },
+  { "bdx_player.pushing.down",                         UNDEFINED_FILENAME              },
+  { "bdx_player.pushing.down.clone_from",              "player_1.pushing.down"         },
+  { "bdx_player.pushing.up",                           UNDEFINED_FILENAME              },
+  { "bdx_player.pushing.up.clone_from",                        "player_1.pushing.up"           },
+  { "bdx_player.pushing.left",                         UNDEFINED_FILENAME              },
+  { "bdx_player.pushing.left.clone_from",              "player_1.pushing.left"         },
+  { "bdx_player.pushing.right",                                UNDEFINED_FILENAME              },
+  { "bdx_player.pushing.right.clone_from",             "player_1.pushing.right"        },
+  { "bdx_player.snapping.down",                                UNDEFINED_FILENAME              },
+  { "bdx_player.snapping.down.clone_from",             "player_1.snapping.down"        },
+  { "bdx_player.snapping.up",                          UNDEFINED_FILENAME              },
+  { "bdx_player.snapping.up.clone_from",               "player_1.snapping.up"          },
+  { "bdx_player.snapping.left",                                UNDEFINED_FILENAME              },
+  { "bdx_player.snapping.left.clone_from",             "player_1.snapping.left"        },
+  { "bdx_player.snapping.right",                       UNDEFINED_FILENAME              },
+  { "bdx_player.snapping.right.clone_from",            "player_1.snapping.right"       },
+
+  { "bdx_player_glued",                                        UNDEFINED_FILENAME              },
+  { "bdx_player_glued.clone_from",                     "bdx_player"                    },
+  { "bdx_player_glued.EDITOR",                         "RocksBD2.png"                  },
+  { "bdx_player_glued.EDITOR.xpos",                    "1"                             },
+  { "bdx_player_glued.EDITOR.ypos",                    "0"                             },
+
+  { "bdx_player_with_bomb",                            "RocksBD.png"                   },
+  { "bdx_player_with_bomb.xpos",                       "8"                             },
+  { "bdx_player_with_bomb.ypos",                       "7"                             },
+  { "bdx_player_with_bomb.frames",                     "1"                             },
+
+  { "bdx_player_with_rocket_launcher",                 "RocksBD.png"                   },
+  { "bdx_player_with_rocket_launcher.xpos",            "10"                            },
+  { "bdx_player_with_rocket_launcher.ypos",            "7"                             },
+  { "bdx_player_with_rocket_launcher.frames",          "1"                             },
+
+  { "bdx_player_stirring",                             "RocksBD.png"                   },
+  { "bdx_player_stirring.xpos",                                "8"                             },
+  { "bdx_player_stirring.ypos",                                "8"                             },
+  { "bdx_player_stirring.frames",                      "4"                             },
+  { "bdx_player_stirring.delay",                       "4"                             },
+
+  { "bdx_wall",                                                UNDEFINED_FILENAME              },
+  { "bdx_wall.clone_from",                             "bd_wall"                       },
+  { "bdx_wall.EDITOR",                                 UNDEFINED_FILENAME              },
+  { "bdx_wall.EDITOR.clone_from",                      "bd_wall.EDITOR"                },
+
+  { "bdx_rock",                                                UNDEFINED_FILENAME              },
+  { "bdx_rock.clone_from",                             "bd_rock"                       },
+  { "bdx_rock.EDITOR",                                 UNDEFINED_FILENAME              },
+  { "bdx_rock.EDITOR.clone_from",                      "bd_rock.EDITOR"                },
+  { "bdx_rock.moving.left",                            UNDEFINED_FILENAME              },
+  { "bdx_rock.moving.left.clone_from",                 "bd_rock.moving.left"           },
+  { "bdx_rock.moving.right",                           UNDEFINED_FILENAME              },
+  { "bdx_rock.moving.right.clone_from",                        "bd_rock.moving.right"          },
+  { "bdx_rock.pushing.left",                           UNDEFINED_FILENAME              },
+  { "bdx_rock.pushing.left.clone_from",                        "bd_rock.pushing.left"          },
+  { "bdx_rock.pushing.right",                          UNDEFINED_FILENAME              },
+  { "bdx_rock.pushing.right.clone_from",               "bd_rock.pushing.right"         },
+  { "bdx_rock.falling.EDITOR",                         "RocksBD2.png"                  },
+  { "bdx_rock.falling.EDITOR.xpos",                    "1"                             },
+  { "bdx_rock.falling.EDITOR.ypos",                    "3"                             },
+
+  { "bdx_diamond",                                     UNDEFINED_FILENAME              },
+  { "bdx_diamond.clone_from",                          "bd_diamond"                    },
+  { "bdx_diamond.moving",                              UNDEFINED_FILENAME              },
+  { "bdx_diamond.moving.clone_from",                   "bd_diamond.moving"             },
+  { "bdx_diamond.falling",                             UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.clone_from",                  "bd_diamond.falling"            },
+  { "bdx_diamond.collecting",                          UNDEFINED_FILENAME              },
+  { "bdx_diamond.collecting.clone_from",               "bd_diamond.collecting"         },
+  { "bdx_diamond.falling.EDITOR",                      "RocksBD2.png"                  },
+  { "bdx_diamond.falling.EDITOR.xpos",                 "0"                             },
+  { "bdx_diamond.falling.EDITOR.ypos",                 "3"                             },
+
+  { "bdx_magic_wall",                                  UNDEFINED_FILENAME              },
+  { "bdx_magic_wall.clone_from",                       "bd_magic_wall"                 },
+  { "bdx_magic_wall.active",                           UNDEFINED_FILENAME              },
+  { "bdx_magic_wall.active.clone_from",                        "bd_magic_wall.active"          },
+
+  { "bdx_amoeba_1",                                    "RocksBD.png"                   },
+  { "bdx_amoeba_1.xpos",                               "4"                             },
+  { "bdx_amoeba_1.ypos",                               "11"                            },
+  { "bdx_amoeba_1.frames",                             "4"                             },
+  { "bdx_amoeba_1.delay",                              "4"                             },
+  { "bdx_amoeba_1.anim_mode",                          "pingpong2"                     },
+
+  { "bdx_amoeba_2",                                    "RocksBD.png"                   },
+  { "bdx_amoeba_2.xpos",                               "8"                             },
+  { "bdx_amoeba_2.ypos",                               "11"                            },
+  { "bdx_amoeba_2.frames",                             "4"                             },
+  { "bdx_amoeba_2.delay",                              "4"                             },
+  { "bdx_amoeba_2.anim_mode",                          "pingpong2"                     },
+
+  { "bdx_butterfly_1",                                 UNDEFINED_FILENAME              },
+  { "bdx_butterfly_1.clone_from",                      "bd_butterfly"                  },
+  { "bdx_butterfly_1.right",                           UNDEFINED_FILENAME              },
+  { "bdx_butterfly_1.right.clone_from",                        "bd_butterfly.right"            },
+  { "bdx_butterfly_1.up",                              UNDEFINED_FILENAME              },
+  { "bdx_butterfly_1.up.clone_from",                   "bd_butterfly.up"               },
+  { "bdx_butterfly_1.left",                            UNDEFINED_FILENAME              },
+  { "bdx_butterfly_1.left.clone_from",                 "bd_butterfly.left"             },
+  { "bdx_butterfly_1.down",                            UNDEFINED_FILENAME              },
+  { "bdx_butterfly_1.down.clone_from",                 "bd_butterfly.down"             },
+
+  { "bdx_butterfly_2",                                 "RocksBD.png"                   },
+  { "bdx_butterfly_2.xpos",                            "0"                             },
+  { "bdx_butterfly_2.ypos",                            "0"                             },
+  { "bdx_butterfly_2.frames",                          "2"                             },
+  { "bdx_butterfly_2.anim_mode",                       "pingpong"                      },
+  { "bdx_butterfly_2.delay",                           "4"                             },
+  { "bdx_butterfly_2.global_sync",                     "true"                          },
+  { "bdx_butterfly_2.right",                           "RocksBD.png"                   },
+  { "bdx_butterfly_2.right.xpos",                      "0"                             },
+  { "bdx_butterfly_2.right.ypos",                      "0"                             },
+  { "bdx_butterfly_2.right.frames",                    "2"                             },
+  { "bdx_butterfly_2.right.anim_mode",                 "pingpong"                      },
+  { "bdx_butterfly_2.right.delay",                     "4"                             },
+  { "bdx_butterfly_2.right.global_sync",               "true"                          },
+  { "bdx_butterfly_2.right.EDITOR",                    "RocksBD.png"                   },
+  { "bdx_butterfly_2.right.EDITOR.xpos",               "4"                             },
+  { "bdx_butterfly_2.right.EDITOR.ypos",               "0"                             },
+  { "bdx_butterfly_2.up",                              "RocksBD.png"                   },
+  { "bdx_butterfly_2.up.xpos",                         "0"                             },
+  { "bdx_butterfly_2.up.ypos",                         "0"                             },
+  { "bdx_butterfly_2.up.frames",                       "2"                             },
+  { "bdx_butterfly_2.up.anim_mode",                    "pingpong"                      },
+  { "bdx_butterfly_2.up.delay",                                "4"                             },
+  { "bdx_butterfly_2.up.global_sync",                  "true"                          },
+  { "bdx_butterfly_2.up.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_butterfly_2.up.EDITOR.xpos",                  "5"                             },
+  { "bdx_butterfly_2.up.EDITOR.ypos",                  "0"                             },
+  { "bdx_butterfly_2.left",                            "RocksBD.png"                   },
+  { "bdx_butterfly_2.left.xpos",                       "0"                             },
+  { "bdx_butterfly_2.left.ypos",                       "0"                             },
+  { "bdx_butterfly_2.left.frames",                     "2"                             },
+  { "bdx_butterfly_2.left.anim_mode",                  "pingpong"                      },
+  { "bdx_butterfly_2.left.delay",                      "4"                             },
+  { "bdx_butterfly_2.left.global_sync",                        "true"                          },
+  { "bdx_butterfly_2.left.EDITOR",                     "RocksBD.png"                   },
+  { "bdx_butterfly_2.left.EDITOR.xpos",                        "6"                             },
+  { "bdx_butterfly_2.left.EDITOR.ypos",                        "0"                             },
+  { "bdx_butterfly_2.down",                            "RocksBD.png"                   },
+  { "bdx_butterfly_2.down.xpos",                       "0"                             },
+  { "bdx_butterfly_2.down.ypos",                       "0"                             },
+  { "bdx_butterfly_2.down.frames",                     "2"                             },
+  { "bdx_butterfly_2.down.anim_mode",                  "pingpong"                      },
+  { "bdx_butterfly_2.down.delay",                      "4"                             },
+  { "bdx_butterfly_2.down.global_sync",                        "true"                          },
+  { "bdx_butterfly_2.down.EDITOR",                     "RocksBD.png"                   },
+  { "bdx_butterfly_2.down.EDITOR.xpos",                        "7"                             },
+  { "bdx_butterfly_2.down.EDITOR.ypos",                        "0"                             },
+
+  { "bdx_firefly_1",                                   UNDEFINED_FILENAME              },
+  { "bdx_firefly_1.clone_from",                                "bd_firefly"                    },
+  { "bdx_firefly_1.right",                             UNDEFINED_FILENAME              },
+  { "bdx_firefly_1.right.clone_from",                  "bd_firefly.right"              },
+  { "bdx_firefly_1.up",                                        UNDEFINED_FILENAME              },
+  { "bdx_firefly_1.up.clone_from",                     "bd_firefly.up"                 },
+  { "bdx_firefly_1.left",                              UNDEFINED_FILENAME              },
+  { "bdx_firefly_1.left.clone_from",                   "bd_firefly.left"               },
+  { "bdx_firefly_1.down",                              UNDEFINED_FILENAME              },
+  { "bdx_firefly_1.down.clone_from",                   "bd_firefly.down"               },
+
+  { "bdx_firefly_2",                                   "RocksBD.png"                   },
+  { "bdx_firefly_2.xpos",                              "2"                             },
+  { "bdx_firefly_2.ypos",                              "0"                             },
+  { "bdx_firefly_2.frames",                            "2"                             },
+  { "bdx_firefly_2.anim_mode",                         "pingpong"                      },
+  { "bdx_firefly_2.delay",                             "4"                             },
+  { "bdx_firefly_2.global_sync",                       "true"                          },
+  { "bdx_firefly_2.right",                             "RocksBD.png"                   },
+  { "bdx_firefly_2.right.xpos",                                "2"                             },
+  { "bdx_firefly_2.right.ypos",                                "0"                             },
+  { "bdx_firefly_2.right.frames",                      "2"                             },
+  { "bdx_firefly_2.right.anim_mode",                   "pingpong"                      },
+  { "bdx_firefly_2.right.delay",                       "4"                             },
+  { "bdx_firefly_2.right.global_sync",                 "true"                          },
+  { "bdx_firefly_2.right.EDITOR",                      "RocksBD.png"                   },
+  { "bdx_firefly_2.right.EDITOR.xpos",                 "8"                             },
+  { "bdx_firefly_2.right.EDITOR.ypos",                 "0"                             },
+  { "bdx_firefly_2.up",                                        "RocksBD.png"                   },
+  { "bdx_firefly_2.up.xpos",                           "2"                             },
+  { "bdx_firefly_2.up.ypos",                           "0"                             },
+  { "bdx_firefly_2.up.frames",                         "2"                             },
+  { "bdx_firefly_2.up.anim_mode",                      "pingpong"                      },
+  { "bdx_firefly_2.up.delay",                          "4"                             },
+  { "bdx_firefly_2.up.global_sync",                    "true"                          },
+  { "bdx_firefly_2.up.EDITOR",                         "RocksBD.png"                   },
+  { "bdx_firefly_2.up.EDITOR.xpos",                    "9"                             },
+  { "bdx_firefly_2.up.EDITOR.ypos",                    "0"                             },
+  { "bdx_firefly_2.left",                              "RocksBD.png"                   },
+  { "bdx_firefly_2.left.xpos",                         "2"                             },
+  { "bdx_firefly_2.left.ypos",                         "0"                             },
+  { "bdx_firefly_2.left.frames",                       "2"                             },
+  { "bdx_firefly_2.left.anim_mode",                    "pingpong"                      },
+  { "bdx_firefly_2.left.delay",                                "4"                             },
+  { "bdx_firefly_2.left.global_sync",                  "true"                          },
+  { "bdx_firefly_2.left.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_firefly_2.left.EDITOR.xpos",                  "10"                            },
+  { "bdx_firefly_2.left.EDITOR.ypos",                  "0"                             },
+  { "bdx_firefly_2.down",                              "RocksBD.png"                   },
+  { "bdx_firefly_2.down.xpos",                         "2"                             },
+  { "bdx_firefly_2.down.ypos",                         "0"                             },
+  { "bdx_firefly_2.down.frames",                       "2"                             },
+  { "bdx_firefly_2.down.anim_mode",                    "pingpong"                      },
+  { "bdx_firefly_2.down.delay",                                "4"                             },
+  { "bdx_firefly_2.down.global_sync",                  "true"                          },
+  { "bdx_firefly_2.down.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_firefly_2.down.EDITOR.xpos",                  "11"                            },
+  { "bdx_firefly_2.down.EDITOR.ypos",                  "0"                             },
+
+  { "bdx_sand_1",                                      UNDEFINED_FILENAME              },
+  { "bdx_sand_1.clone_from",                           "sand"                          },
+
+  { "bdx_sand_2",                                      UNDEFINED_FILENAME              },
+  { "bdx_sand_2.clone_from",                           "emc_grass"                     },
+
+  { "bdx_sand_ball",                                   "RocksBD.png"                   },
+  { "bdx_sand_ball.xpos",                              "9"                             },
+  { "bdx_sand_ball.ypos",                              "4"                             },
+  { "bdx_sand_ball.frames",                            "1"                             },
+
+  { "bdx_sand_loose",                                  "RocksBD.png"                   },
+  { "bdx_sand_loose.xpos",                             "10"                            },
+  { "bdx_sand_loose.ypos",                             "4"                             },
+  { "bdx_sand_loose.frames",                           "1"                             },
+
+  { "bdx_sand_sloped_up_left",                         "RocksBD.png"                   },
+  { "bdx_sand_sloped_up_left.xpos",                    "8"                             },
+  { "bdx_sand_sloped_up_left.ypos",                    "5"                             },
+  { "bdx_sand_sloped_up_left.frames",                  "1"                             },
+  { "bdx_sand_sloped_up_right",                                "RocksBD.png"                   },
+  { "bdx_sand_sloped_up_right.xpos",                   "9"                             },
+  { "bdx_sand_sloped_up_right.ypos",                   "5"                             },
+  { "bdx_sand_sloped_up_right.frames",                 "1"                             },
+  { "bdx_sand_sloped_down_left",                       "RocksBD.png"                   },
+  { "bdx_sand_sloped_down_left.xpos",                  "10"                            },
+  { "bdx_sand_sloped_down_left.ypos",                  "5"                             },
+  { "bdx_sand_sloped_down_left.frames",                        "1"                             },
+  { "bdx_sand_sloped_down_right",                      "RocksBD.png"                   },
+  { "bdx_sand_sloped_down_right.xpos",                 "11"                            },
+  { "bdx_sand_sloped_down_right.ypos",                 "5"                             },
+  { "bdx_sand_sloped_down_right.frames",               "1"                             },
+
+  { "bdx_sand_glued",                                  UNDEFINED_FILENAME              },
+  { "bdx_sand_glued.clone_from",                       "bdx_sand_1"                    },
+  { "bdx_sand_glued.EDITOR",                           "RocksBD2.png"                  },
+  { "bdx_sand_glued.EDITOR.xpos",                      "2"                             },
+  { "bdx_sand_glued.EDITOR.ypos",                      "4"                             },
+
+  { "bdx_wall_sloped_up_left",                         "RocksBD.png"                   },
+  { "bdx_wall_sloped_up_left.xpos",                    "4"                             },
+  { "bdx_wall_sloped_up_left.ypos",                    "5"                             },
+  { "bdx_wall_sloped_up_left.frames",                  "1"                             },
+  { "bdx_wall_sloped_up_right",                                "RocksBD.png"                   },
+  { "bdx_wall_sloped_up_right.xpos",                   "5"                             },
+  { "bdx_wall_sloped_up_right.ypos",                   "5"                             },
+  { "bdx_wall_sloped_up_right.frames",                 "1"                             },
+  { "bdx_wall_sloped_down_left",                       "RocksBD.png"                   },
+  { "bdx_wall_sloped_down_left.xpos",                  "6"                             },
+  { "bdx_wall_sloped_down_left.ypos",                  "5"                             },
+  { "bdx_wall_sloped_down_left.frames",                        "1"                             },
+  { "bdx_wall_sloped_down_right",                      "RocksBD.png"                   },
+  { "bdx_wall_sloped_down_right.xpos",                 "7"                             },
+  { "bdx_wall_sloped_down_right.ypos",                 "5"                             },
+  { "bdx_wall_sloped_down_right.frames",               "1"                             },
+
+  { "bdx_wall_non_sloped",                             UNDEFINED_FILENAME              },
+  { "bdx_wall_non_sloped.clone_from",                  "wall"                          },
+
+  { "bdx_wall_diggable",                               UNDEFINED_FILENAME              },
+  { "bdx_wall_diggable.clone_from",                    "bdx_wall"                      },
+  { "bdx_wall_diggable.EDITOR",                                "RocksBD2.png"                  },
+  { "bdx_wall_diggable.EDITOR.xpos",                   "7"                             },
+  { "bdx_wall_diggable.EDITOR.ypos",                   "0"                             },
+
+  { "bdx_wall_diamond",                                        UNDEFINED_FILENAME              },
+  { "bdx_wall_diamond.clone_from",                     "bdx_wall"                      },
+  { "bdx_wall_diamond.EDITOR",                         "RocksBD2.png"                  },
+  { "bdx_wall_diamond.EDITOR.xpos",                    "3"                             },
+  { "bdx_wall_diamond.EDITOR.ypos",                    "2"                             },
+
+  { "bdx_wall_key_1",                                  UNDEFINED_FILENAME              },
+  { "bdx_wall_key_1.clone_from",                       "bdx_wall"                      },
+  { "bdx_wall_key_1.EDITOR",                           "RocksBD2.png"                  },
+  { "bdx_wall_key_1.EDITOR.xpos",                      "0"                             },
+  { "bdx_wall_key_1.EDITOR.ypos",                      "2"                             },
+
+  { "bdx_wall_key_2",                                  UNDEFINED_FILENAME              },
+  { "bdx_wall_key_2.clone_from",                       "bdx_wall"                      },
+  { "bdx_wall_key_2.EDITOR",                           "RocksBD2.png"                  },
+  { "bdx_wall_key_2.EDITOR.xpos",                      "1"                             },
+  { "bdx_wall_key_2.EDITOR.ypos",                      "2"                             },
+
+  { "bdx_wall_key_3",                                  UNDEFINED_FILENAME              },
+  { "bdx_wall_key_3.clone_from",                       "bdx_wall"                      },
+  { "bdx_wall_key_3.EDITOR",                           "RocksBD2.png"                  },
+  { "bdx_wall_key_3.EDITOR.xpos",                      "2"                             },
+  { "bdx_wall_key_3.EDITOR.ypos",                      "2"                             },
+
+  { "bdx_falling_wall",                                        UNDEFINED_FILENAME              },
+  { "bdx_falling_wall.clone_from",                     "bdx_wall"                      },
+  { "bdx_falling_wall.EDITOR",                         "RocksBD2.png"                  },
+  { "bdx_falling_wall.EDITOR.xpos",                    "6"                             },
+  { "bdx_falling_wall.EDITOR.ypos",                    "1"                             },
+  { "bdx_falling_wall.falling.EDITOR",                 "RocksBD2.png"                  },
+  { "bdx_falling_wall.falling.EDITOR.xpos",            "7"                             },
+  { "bdx_falling_wall.falling.EDITOR.ypos",            "1"                             },
+
+  { "bdx_steelwall",                                   "RocksBD.png"                   },
+  { "bdx_steelwall.xpos",                              "8"                             },
+  { "bdx_steelwall.ypos",                              "3"                             },
+  { "bdx_steelwall.frames",                            "1"                             },
+
+  { "bdx_steelwall_sloped_up_left",                    "RocksBD.png"                   },
+  { "bdx_steelwall_sloped_up_left.xpos",               "0"                             },
+  { "bdx_steelwall_sloped_up_left.ypos",               "5"                             },
+  { "bdx_steelwall_sloped_up_left.frames",             "1"                             },
+  { "bdx_steelwall_sloped_up_right",                   "RocksBD.png"                   },
+  { "bdx_steelwall_sloped_up_right.xpos",              "1"                             },
+  { "bdx_steelwall_sloped_up_right.ypos",              "5"                             },
+  { "bdx_steelwall_sloped_up_right.frames",            "1"                             },
+  { "bdx_steelwall_sloped_down_left",                  "RocksBD.png"                   },
+  { "bdx_steelwall_sloped_down_left.xpos",             "2"                             },
+  { "bdx_steelwall_sloped_down_left.ypos",             "5"                             },
+  { "bdx_steelwall_sloped_down_left.frames",           "1"                             },
+  { "bdx_steelwall_sloped_down_right",                 "RocksBD.png"                   },
+  { "bdx_steelwall_sloped_down_right.xpos",            "3"                             },
+  { "bdx_steelwall_sloped_down_right.ypos",            "5"                             },
+  { "bdx_steelwall_sloped_down_right.frames",          "1"                             },
+
+  { "bdx_steelwall_explodable",                                UNDEFINED_FILENAME              },
+  { "bdx_steelwall_explodable.clone_from",             "bd_steelwall"                  },
+
+  { "bdx_steelwall_diggable",                          UNDEFINED_FILENAME              },
+  { "bdx_steelwall_diggable.clone_from",               "bd_steelwall"                  },
+  { "bdx_steelwall_diggable.EDITOR",                   "RocksBD2.png"                  },
+  { "bdx_steelwall_diggable.EDITOR.xpos",              "6"                             },
+  { "bdx_steelwall_diggable.EDITOR.ypos",              "0"                             },
+
+  { "bdx_expandable_wall_horizontal",                  UNDEFINED_FILENAME              },
+  { "bdx_expandable_wall_horizontal.clone_from",       "bd_wall"                       },
+  { "bdx_expandable_wall_horizontal.EDITOR",           "RocksBD2.png"                  },
+  { "bdx_expandable_wall_horizontal.EDITOR.xpos",      "3"                             },
+  { "bdx_expandable_wall_horizontal.EDITOR.ypos",      "1"                             },
+
+  { "bdx_expandable_wall_vertical",                    UNDEFINED_FILENAME              },
+  { "bdx_expandable_wall_vertical.clone_from",         "bd_wall"                       },
+  { "bdx_expandable_wall_vertical.EDITOR",             "RocksBD2.png"                  },
+  { "bdx_expandable_wall_vertical.EDITOR.xpos",                "4"                             },
+  { "bdx_expandable_wall_vertical.EDITOR.ypos",                "1"                             },
+
+  { "bdx_expandable_wall_any",                         UNDEFINED_FILENAME              },
+  { "bdx_expandable_wall_any.clone_from",              "bd_wall"                       },
+  { "bdx_expandable_wall_any.EDITOR",                  "RocksBD2.png"                  },
+  { "bdx_expandable_wall_any.EDITOR.xpos",             "5"                             },
+  { "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.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.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.EDITOR",             "RocksBD2.png"                  },
+  { "bdx_expandable_steelwall_any.EDITOR.xpos",                "2"                             },
+  { "bdx_expandable_steelwall_any.EDITOR.ypos",                "1"                             },
+
+  { "bdx_expandable_wall_switch",                      "RocksBD.png"                   },
+  { "bdx_expandable_wall_switch.xpos",                 "10"                            },
+  { "bdx_expandable_wall_switch.ypos",                 "3"                             },
+  { "bdx_expandable_wall_switch.frames",               "1"                             },
+
+  { "bdx_expandable_wall_switch.active",               "RocksBD.png"                   },
+  { "bdx_expandable_wall_switch.active.xpos",          "11"                            },
+  { "bdx_expandable_wall_switch.active.ypos",          "3"                             },
+  { "bdx_expandable_wall_switch.active.frames",                "1"                             },
+
+  { "bdx_inbox",                                       "RocksBD.png"                   },
+  { "bdx_inbox.xpos",                                  "8"                             },
+  { "bdx_inbox.ypos",                                  "3"                             },
+  { "bdx_inbox.frames",                                        "1"                             },
+  { "bdx_inbox.opening",                               "RocksBD.png"                   },
+  { "bdx_inbox.opening.xpos",                          "8"                             },
+  { "bdx_inbox.opening.ypos",                          "3"                             },
+  { "bdx_inbox.opening.frames",                                "2"                             },
+  { "bdx_inbox.opening.delay",                         "8"                             },
+  { "bdx_inbox.opening.anim_mode",                     "reverse"                       },
+  { "bdx_inbox.EDITOR",                                        "RocksBD2.png"                  },
+  { "bdx_inbox.EDITOR.xpos",                           "0"                             },
+  { "bdx_inbox.EDITOR.ypos",                           "0"                             },
+
+  { "bdx_exit_closed",                                 "RocksBD.png"                   },
+  { "bdx_exit_closed.xpos",                            "8"                             },
+  { "bdx_exit_closed.ypos",                            "3"                             },
+  { "bdx_exit_closed.frames",                          "1"                             },
+  { "bdx_exit_closed.EDITOR",                          "RocksBD2.png"                  },
+  { "bdx_exit_closed.EDITOR.xpos",                     "5"                             },
+  { "bdx_exit_closed.EDITOR.ypos",                     "0"                             },
+
+  { "bdx_exit_open",                                   "RocksBD.png"                   },
+  { "bdx_exit_open.xpos",                              "8"                             },
+  { "bdx_exit_open.ypos",                              "3"                             },
+  { "bdx_exit_open.frames",                            "2"                             },
+  { "bdx_exit_open.delay",                             "8"                             },
+  { "bdx_exit_open.anim_mode",                         "reverse"                       },
+  { "bdx_exit_open.EDITOR",                            "RocksBD2.png"                  },
+  { "bdx_exit_open.EDITOR.xpos",                       "3"                             },
+  { "bdx_exit_open.EDITOR.ypos",                       "0"                             },
+
+  { "bdx_invisible_exit_closed",                       UNDEFINED_FILENAME              },
+  { "bdx_invisible_exit_closed.clone_from",            "bd_steelwall"                  },
+  { "bdx_invisible_exit_closed.EDITOR",                        "RocksBD2.png"                  },
+  { "bdx_invisible_exit_closed.EDITOR.xpos",           "4"                             },
+  { "bdx_invisible_exit_closed.EDITOR.ypos",           "0"                             },
+
+  { "bdx_invisible_exit_open",                         UNDEFINED_FILENAME              },
+  { "bdx_invisible_exit_open.clone_from",              "bd_steelwall"                  },
+  { "bdx_invisible_exit_open.EDITOR",                  "RocksBD2.png"                  },
+  { "bdx_invisible_exit_open.EDITOR.xpos",             "2"                             },
+  { "bdx_invisible_exit_open.EDITOR.ypos",             "0"                             },
+
+  { "bdx_flying_rock",                                 "RocksBD.png"                   },
+  { "bdx_flying_rock.xpos",                            "1"                             },
+  { "bdx_flying_rock.ypos",                            "4"                             },
+  { "bdx_flying_rock.frames",                          "1"                             },
+  { "bdx_flying_rock.flying.EDITOR",                   "RocksBD2.png"                  },
+  { "bdx_flying_rock.flying.EDITOR.xpos",              "4"                             },
+  { "bdx_flying_rock.flying.EDITOR.ypos",              "3"                             },
+
+  { "bdx_mega_rock",                                   "RocksBD.png"                   },
+  { "bdx_mega_rock.xpos",                              "2"                             },
+  { "bdx_mega_rock.ypos",                              "4"                             },
+  { "bdx_mega_rock.frames",                            "1"                             },
+  { "bdx_mega_rock.falling.EDITOR",                    "RocksBD2.png"                  },
+  { "bdx_mega_rock.falling.EDITOR.xpos",               "2"                             },
+  { "bdx_mega_rock.falling.EDITOR.ypos",               "3"                             },
+
+  { "bdx_rock_glued",                                  UNDEFINED_FILENAME              },
+  { "bdx_rock_glued.clone_from",                       "bd_rock"                       },
+  { "bdx_rock_glued.EDITOR",                           "RocksBD2.png"                  },
+  { "bdx_rock_glued.EDITOR.xpos",                      "1"                             },
+  { "bdx_rock_glued.EDITOR.ypos",                      "4"                             },
+
+  { "bdx_flying_diamond",                              "RocksBD.png"                   },
+  { "bdx_flying_diamond.xpos",                         "0"                             },
+  { "bdx_flying_diamond.ypos",                         "3"                             },
+  { "bdx_flying_diamond.frames",                       "4"                             },
+  { "bdx_flying_diamond.delay",                                "4"                             },
+  { "bdx_flying_diamond.moving",                       "RocksBD.png"                   },
+  { "bdx_flying_diamond.moving.xpos",                  "3"                             },
+  { "bdx_flying_diamond.moving.ypos",                  "3"                             },
+  { "bdx_flying_diamond.moving.frames",                        "2"                             },
+  { "bdx_flying_diamond.moving.delay",                 "4"                             },
+  { "bdx_flying_diamond.flying",                       "RocksBD.png"                   },
+  { "bdx_flying_diamond.flying.xpos",                  "3"                             },
+  { "bdx_flying_diamond.flying.ypos",                  "3"                             },
+  { "bdx_flying_diamond.flying.frames",                        "2"                             },
+  { "bdx_flying_diamond.flying.delay",                 "4"                             },
+  { "bdx_flying_diamond.flying.EDITOR",                        "RocksBD2.png"                  },
+  { "bdx_flying_diamond.flying.EDITOR.xpos",           "3"                             },
+  { "bdx_flying_diamond.flying.EDITOR.ypos",           "3"                             },
+
+  { "bdx_diamond_glued",                               UNDEFINED_FILENAME              },
+  { "bdx_diamond_glued.clone_from",                    "bd_diamond"                    },
+  { "bdx_diamond_glued.EDITOR",                                "RocksBD2.png"                  },
+  { "bdx_diamond_glued.EDITOR.xpos",                   "0"                             },
+  { "bdx_diamond_glued.EDITOR.ypos",                   "4"                             },
+
+  { "bdx_diamond_key",                                 "RocksBD.png"                   },
+  { "bdx_diamond_key.xpos",                            "1"                             },
+  { "bdx_diamond_key.ypos",                            "6"                             },
+  { "bdx_diamond_key.frames",                          "1"                             },
+
+  { "bdx_trapped_diamond",                             "RocksBD.png"                   },
+  { "bdx_trapped_diamond.xpos",                                "0"                             },
+  { "bdx_trapped_diamond.ypos",                                "6"                             },
+  { "bdx_trapped_diamond.frames",                      "1"                             },
+
+  { "bdx_nut",                                         UNDEFINED_FILENAME              },
+  { "bdx_nut.clone_from",                              "nut"                           },
+  { "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_bladder_spender",                             "RocksBD.png"                   },
+  { "bdx_bladder_spender.xpos",                                "11"                            },
+  { "bdx_bladder_spender.ypos",                                "10"                            },
+  { "bdx_bladder_spender.frames",                      "1"                             },
+
+  { "bdx_creature_switch",                             "RocksBD.png"                   },
+  { "bdx_creature_switch.xpos",                                "9"                             },
+  { "bdx_creature_switch.ypos",                                "9"                             },
+  { "bdx_creature_switch.frames",                      "1"                             },
+  { "bdx_creature_switch.active",                      "RocksBD.png"                   },
+  { "bdx_creature_switch.active.xpos",                 "10"                            },
+  { "bdx_creature_switch.active.ypos",                 "9"                             },
+  { "bdx_creature_switch.active.frames",               "1"                             },
+
+  { "bdx_biter_switch_1",                              "RocksBD.png"                   },
+  { "bdx_biter_switch_1.xpos",                         "4"                             },
+  { "bdx_biter_switch_1.ypos",                         "4"                             },
+  { "bdx_biter_switch_1.frames",                       "1"                             },
+
+  { "bdx_biter_switch_2",                              "RocksBD.png"                   },
+  { "bdx_biter_switch_2.xpos",                         "5"                             },
+  { "bdx_biter_switch_2.ypos",                         "4"                             },
+  { "bdx_biter_switch_2.frames",                       "1"                             },
+
+  { "bdx_biter_switch_3",                              "RocksBD.png"                   },
+  { "bdx_biter_switch_3.xpos",                         "6"                             },
+  { "bdx_biter_switch_3.ypos",                         "4"                             },
+  { "bdx_biter_switch_3.frames",                       "1"                             },
+
+  { "bdx_biter_switch_4",                              "RocksBD.png"                   },
+  { "bdx_biter_switch_4.xpos",                         "7"                             },
+  { "bdx_biter_switch_4.ypos",                         "4"                             },
+  { "bdx_biter_switch_4.frames",                       "1"                             },
+
+  { "bdx_replicator",                                  UNDEFINED_FILENAME              },
+  { "bdx_replicator.clone_from",                       "emc_magic_ball"                },
+  { "bdx_replicator.active",                           UNDEFINED_FILENAME              },
+  { "bdx_replicator.active.clone_from",                        "emc_magic_ball.active"         },
+
+  { "bdx_replicator_switch",                           UNDEFINED_FILENAME              },
+  { "bdx_replicator_switch.clone_from",                        "emc_magic_ball_switch"         },
+  { "bdx_replicator_switch.active",                    UNDEFINED_FILENAME              },
+  { "bdx_replicator_switch.active.clone_from",         "emc_magic_ball_switch.active"  },
+
+  { "bdx_conveyor_left",                               "RocksDC.png"                   },
+  { "bdx_conveyor_left.xpos",                          "0"                             },
+  { "bdx_conveyor_left.ypos",                          "3"                             },
+  { "bdx_conveyor_left.frames",                                "1"                             },
+  { "bdx_conveyor_left.EDITOR",                                "RocksBD2.png"                  },
+  { "bdx_conveyor_left.EDITOR.xpos",                   "6"                             },
+  { "bdx_conveyor_left.EDITOR.ypos",                   "3"                             },
+  { "bdx_conveyor_left.active",                                "RocksDC.png"                   },
+  { "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_right",                              "RocksDC.png"                   },
+  { "bdx_conveyor_right.xpos",                         "0"                             },
+  { "bdx_conveyor_right.ypos",                         "3"                             },
+  { "bdx_conveyor_right.frames",                       "1"                             },
+  { "bdx_conveyor_right.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_conveyor_right.EDITOR.xpos",                  "7"                             },
+  { "bdx_conveyor_right.EDITOR.ypos",                  "3"                             },
+  { "bdx_conveyor_right.active",                       "RocksDC.png"                   },
+  { "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.anim_mode",             "reverse"                       },
+
+  { "bdx_conveyor_switch",                             "RocksBD.png"                   },
+  { "bdx_conveyor_switch.xpos",                                "8"                             },
+  { "bdx_conveyor_switch.ypos",                                "2"                             },
+  { "bdx_conveyor_switch.frames",                      "1"                             },
+  { "bdx_conveyor_switch.active",                      "RocksBD.png"                   },
+  { "bdx_conveyor_switch.active.xpos",                 "9"                             },
+  { "bdx_conveyor_switch.active.ypos",                 "2"                             },
+  { "bdx_conveyor_switch.active.frames",               "1"                             },
+
+  { "bdx_conveyor_dir_switch",                         "RocksBD.png"                   },
+  { "bdx_conveyor_dir_switch.xpos",                    "10"                            },
+  { "bdx_conveyor_dir_switch.ypos",                    "2"                             },
+  { "bdx_conveyor_dir_switch.frames",                  "1"                             },
+  { "bdx_conveyor_dir_switch.active",                  "RocksBD.png"                   },
+  { "bdx_conveyor_dir_switch.active.xpos",             "11"                            },
+  { "bdx_conveyor_dir_switch.active.ypos",             "2"                             },
+  { "bdx_conveyor_dir_switch.active.frames",           "1"                             },
+
+  { "bdx_gravity_switch",                              "RocksBD.png"                   },
+  { "bdx_gravity_switch.xpos",                         "8"                             },
+  { "bdx_gravity_switch.ypos",                         "10"                            },
+  { "bdx_gravity_switch.frames",                       "1"                             },
+  { "bdx_gravity_switch.active",                       "RocksBD.png"                   },
+  { "bdx_gravity_switch.active.xpos",                  "9"                             },
+  { "bdx_gravity_switch.active.ypos",                  "10"                            },
+  { "bdx_gravity_switch.active.frames",                        "1"                             },
+
+  { "bdx_acid",                                                UNDEFINED_FILENAME              },
+  { "bdx_acid.clone_from",                             "amoeba_dead"                   },
+
+  { "bdx_box",                                         "RocksBD.png"                   },
+  { "bdx_box.xpos",                                    "8"                             },
+  { "bdx_box.ypos",                                    "9"                             },
+  { "bdx_box.frames",                                  "1"                             },
+
+  { "bdx_time_penalty",                                        "RocksBD.png"                   },
+  { "bdx_time_penalty.xpos",                           "3"                             },
+  { "bdx_time_penalty.ypos",                           "6"                             },
+  { "bdx_time_penalty.frames",                         "1"                             },
+
+  { "bdx_gravestone",                                  "RocksBD.png"                   },
+  { "bdx_gravestone.xpos",                             "3"                             },
+  { "bdx_gravestone.ypos",                             "6"                             },
+  { "bdx_gravestone.frames",                           "1"                             },
+
+  { "bdx_clock",                                       "RocksBD.png"                   },
+  { "bdx_clock.xpos",                                  "4"                             },
+  { "bdx_clock.ypos",                                  "6"                             },
+  { "bdx_clock.frames",                                        "1"                             },
+
+  { "bdx_pot",                                         "RocksBD.png"                   },
+  { "bdx_pot.xpos",                                    "6"                             },
+  { "bdx_pot.ypos",                                    "6"                             },
+  { "bdx_pot.frames",                                  "1"                             },
+
+  { "bdx_pneumatic_hammer",                            "RocksBD.png"                   },
+  { "bdx_pneumatic_hammer.xpos",                       "11"                            },
+  { "bdx_pneumatic_hammer.ypos",                       "9"                             },
+  { "bdx_pneumatic_hammer.frames",                     "1"                             },
+  { "bdx_pneumatic_hammer.hitting.left",               "RocksBD.png"                   },
+  { "bdx_pneumatic_hammer.hitting.left.xpos",          "4"                             },
+  { "bdx_pneumatic_hammer.hitting.left.ypos",          "12"                            },
+  { "bdx_pneumatic_hammer.hitting.left.frames",                "2"                             },
+  { "bdx_pneumatic_hammer.hitting.left.delay",         "4"                             },
+  { "bdx_pneumatic_hammer.hitting.left.offset",                "64"                            },
+  { "bdx_pneumatic_hammer.hitting.right",              "RocksBD.png"                   },
+  { "bdx_pneumatic_hammer.hitting.right.xpos",         "1"                             },
+  { "bdx_pneumatic_hammer.hitting.right.ypos",         "12"                            },
+  { "bdx_pneumatic_hammer.hitting.right.frames",       "2"                             },
+  { "bdx_pneumatic_hammer.hitting.right.delay",                "4"                             },
+  { "bdx_pneumatic_hammer.hitting.right.offset",       "64"                            },
+
+  { "bdx_player.hitting.left",                         "RocksBD.png"                   },
+  { "bdx_player.hitting.left.xpos",                    "5"                             },
+  { "bdx_player.hitting.left.ypos",                    "12"                            },
+  { "bdx_player.hitting.left.frames",                  "2"                             },
+  { "bdx_player.hitting.left.delay",                   "4"                             },
+  { "bdx_player.hitting.left.offset",                  "64"                            },
+  { "bdx_player.hitting.right",                                "RocksBD.png"                   },
+  { "bdx_player.hitting.right.xpos",                   "0"                             },
+  { "bdx_player.hitting.right.ypos",                   "12"                            },
+  { "bdx_player.hitting.right.frames",                 "2"                             },
+  { "bdx_player.hitting.right.delay",                  "4"                             },
+  { "bdx_player.hitting.right.offset",                 "64"                            },
+
+  { "bdx_teleporter",                                  "RocksBD.png"                   },
+  { "bdx_teleporter.xpos",                             "2"                             },
+  { "bdx_teleporter.ypos",                             "6"                             },
+  { "bdx_teleporter.frames",                           "1"                             },
+
+  { "bdx_skeleton",                                    "RocksBD.png"                   },
+  { "bdx_skeleton.xpos",                               "7"                             },
+  { "bdx_skeleton.ypos",                               "6"                             },
+  { "bdx_skeleton.frames",                             "1"                             },
+
+  { "bdx_water",                                       "RocksBD.png"                   },
+  { "bdx_water.xpos",                                  "0"                             },
+  { "bdx_water.ypos",                                  "9"                             },
+  { "bdx_water.frames",                                        "8"                             },
+  { "bdx_water.delay",                                 "2"                             },
+
+  { "bdx_key_1",                                       UNDEFINED_FILENAME              },
+  { "bdx_key_1.clone_from",                            "key_2"                         },
+
+  { "bdx_key_2",                                       UNDEFINED_FILENAME              },
+  { "bdx_key_2.clone_from",                            "key_3"                         },
+
+  { "bdx_key_3",                                       UNDEFINED_FILENAME              },
+  { "bdx_key_3.clone_from",                            "key_1"                         },
+
+  { "bdx_gate_1",                                      "RocksBD.png"                   },
+  { "bdx_gate_1.xpos",                                 "5"                             },
+  { "bdx_gate_1.ypos",                                 "3"                             },
+  { "bdx_gate_1.frames",                               "1"                             },
+
+  { "bdx_gate_2",                                      "RocksBD.png"                   },
+  { "bdx_gate_2.xpos",                                 "6"                             },
+  { "bdx_gate_2.ypos",                                 "3"                             },
+  { "bdx_gate_2.frames",                               "1"                             },
+
+  { "bdx_gate_3",                                      "RocksBD.png"                   },
+  { "bdx_gate_3.xpos",                                 "7"                             },
+  { "bdx_gate_3.ypos",                                 "3"                             },
+  { "bdx_gate_3.frames",                               "1"                             },
+
+  { "bdx_lava",                                                UNDEFINED_FILENAME              },
+  { "bdx_lava.clone_from",                             "acid"                          },
+
+  { "bdx_sweet",                                       "RocksBD.png"                   },
+  { "bdx_sweet.xpos",                                  "5"                             },
+  { "bdx_sweet.ypos",                                  "6"                             },
+  { "bdx_sweet.frames",                                        "1"                             },
+
+  { "bdx_voodoo_doll",                                 "RocksBD.png"                   },
+  { "bdx_voodoo_doll.xpos",                            "11"                            },
+  { "bdx_voodoo_doll.ypos",                            "7"                             },
+  { "bdx_voodoo_doll.frames",                          "1"                             },
+
+  { "bdx_slime",                                       "RocksBD.png"                   },
+  { "bdx_slime.xpos",                                  "0"                             },
+  { "bdx_slime.ypos",                                  "11"                            },
+  { "bdx_slime.frames",                                        "4"                             },
+  { "bdx_slime.delay",                                 "4"                             },
+  { "bdx_slime.anim_mode",                             "pingpong2"                     },
+
+  { "bdx_waiting_rock",                                        UNDEFINED_FILENAME              },
+  { "bdx_waiting_rock.clone_from",                     "bdx_rock"                      },
+  { "bdx_waiting_rock.EDITOR",                         "RocksBD2.png"                  },
+  { "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_ghost",                                       "RocksBD.png"                   },
+  { "bdx_ghost.xpos",                                  "0"                             },
+  { "bdx_ghost.ypos",                                  "10"                            },
+  { "bdx_ghost.frames",                                        "8"                             },
+  { "bdx_ghost.delay",                                 "2"                             },
+
+  { "bdx_cow",                                         "RocksBD.png"                   },
+  { "bdx_cow.xpos",                                    "4"                             },
+  { "bdx_cow.ypos",                                    "8"                             },
+  { "bdx_cow.frames",                                  "4"                             },
+  { "bdx_cow.delay",                                   "2"                             },
+  { "bdx_cow.left",                                    "RocksBD.png"                   },
+  { "bdx_cow.left.xpos",                               "4"                             },
+  { "bdx_cow.left.ypos",                               "8"                             },
+  { "bdx_cow.left.frames",                             "4"                             },
+  { "bdx_cow.left.delay",                              "2"                             },
+  { "bdx_cow.left.EDITOR",                             "RocksBD2.png"                  },
+  { "bdx_cow.left.EDITOR.xpos",                                "6"                             },
+  { "bdx_cow.left.EDITOR.ypos",                                "4"                             },
+  { "bdx_cow.up",                                      "RocksBD.png"                   },
+  { "bdx_cow.up.xpos",                                 "4"                             },
+  { "bdx_cow.up.ypos",                                 "8"                             },
+  { "bdx_cow.up.frames",                               "4"                             },
+  { "bdx_cow.up.delay",                                        "2"                             },
+  { "bdx_cow.up.EDITOR",                               "RocksBD2.png"                  },
+  { "bdx_cow.up.EDITOR.xpos",                          "4"                             },
+  { "bdx_cow.up.EDITOR.ypos",                          "4"                             },
+  { "bdx_cow.right",                                   "RocksBD.png"                   },
+  { "bdx_cow.right.xpos",                              "4"                             },
+  { "bdx_cow.right.ypos",                              "8"                             },
+  { "bdx_cow.right.frames",                            "4"                             },
+  { "bdx_cow.right.delay",                             "2"                             },
+  { "bdx_cow.right.EDITOR",                            "RocksBD2.png"                  },
+  { "bdx_cow.right.EDITOR.xpos",                       "7"                             },
+  { "bdx_cow.right.EDITOR.ypos",                       "4"                             },
+  { "bdx_cow.down",                                    "RocksBD.png"                   },
+  { "bdx_cow.down.xpos",                               "4"                             },
+  { "bdx_cow.down.ypos",                               "8"                             },
+  { "bdx_cow.down.frames",                             "4"                             },
+  { "bdx_cow.down.delay",                              "2"                             },
+  { "bdx_cow.down.EDITOR",                             "RocksBD2.png"                  },
+  { "bdx_cow.down.EDITOR.xpos",                                "5"                             },
+  { "bdx_cow.down.EDITOR.ypos",                                "4"                             },
+
+  { "bdx_cow_enclosed_1.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_1.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_1.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_2.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_2.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_2.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_3.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_3.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_3.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_4.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_4.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_4.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_5.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_5.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_5.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_6.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_6.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_6.EDITOR.ypos",                  "4"                             },
+  { "bdx_cow_enclosed_7.EDITOR",                       "RocksBD2.png"                  },
+  { "bdx_cow_enclosed_7.EDITOR.xpos",                  "3"                             },
+  { "bdx_cow_enclosed_7.EDITOR.ypos",                  "4"                             },
+
+  { "bdx_stonefly",                                    "RocksBD.png"                   },
+  { "bdx_stonefly.xpos",                               "0"                             },
+  { "bdx_stonefly.ypos",                               "1"                             },
+  { "bdx_stonefly.frames",                             "2"                             },
+  { "bdx_stonefly.anim_mode",                          "pingpong"                      },
+  { "bdx_stonefly.delay",                              "4"                             },
+  { "bdx_stonefly.global_sync",                                "true"                          },
+  { "bdx_stonefly.right",                              "RocksBD.png"                   },
+  { "bdx_stonefly.right.xpos",                         "0"                             },
+  { "bdx_stonefly.right.ypos",                         "1"                             },
+  { "bdx_stonefly.right.frames",                       "2"                             },
+  { "bdx_stonefly.right.anim_mode",                    "pingpong"                      },
+  { "bdx_stonefly.right.delay",                                "4"                             },
+  { "bdx_stonefly.right.global_sync",                  "true"                          },
+  { "bdx_stonefly.right.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_stonefly.right.EDITOR.xpos",                  "4"                             },
+  { "bdx_stonefly.right.EDITOR.ypos",                  "1"                             },
+  { "bdx_stonefly.up",                                 "RocksBD.png"                   },
+  { "bdx_stonefly.up.xpos",                            "0"                             },
+  { "bdx_stonefly.up.ypos",                            "1"                             },
+  { "bdx_stonefly.up.frames",                          "2"                             },
+  { "bdx_stonefly.up.anim_mode",                       "pingpong"                      },
+  { "bdx_stonefly.up.delay",                           "4"                             },
+  { "bdx_stonefly.up.global_sync",                     "true"                          },
+  { "bdx_stonefly.up.EDITOR",                          "RocksBD.png"                   },
+  { "bdx_stonefly.up.EDITOR.xpos",                     "5"                             },
+  { "bdx_stonefly.up.EDITOR.ypos",                     "1"                             },
+  { "bdx_stonefly.left",                               "RocksBD.png"                   },
+  { "bdx_stonefly.left.xpos",                          "0"                             },
+  { "bdx_stonefly.left.ypos",                          "1"                             },
+  { "bdx_stonefly.left.frames",                                "2"                             },
+  { "bdx_stonefly.left.anim_mode",                     "pingpong"                      },
+  { "bdx_stonefly.left.delay",                         "4"                             },
+  { "bdx_stonefly.left.global_sync",                   "true"                          },
+  { "bdx_stonefly.left.EDITOR",                                "RocksBD.png"                   },
+  { "bdx_stonefly.left.EDITOR.xpos",                   "6"                             },
+  { "bdx_stonefly.left.EDITOR.ypos",                   "1"                             },
+  { "bdx_stonefly.down",                               "RocksBD.png"                   },
+  { "bdx_stonefly.down.xpos",                          "0"                             },
+  { "bdx_stonefly.down.ypos",                          "1"                             },
+  { "bdx_stonefly.down.frames",                                "2"                             },
+  { "bdx_stonefly.down.anim_mode",                     "pingpong"                      },
+  { "bdx_stonefly.down.delay",                         "4"                             },
+  { "bdx_stonefly.down.global_sync",                   "true"                          },
+  { "bdx_stonefly.down.EDITOR",                                "RocksBD.png"                   },
+  { "bdx_stonefly.down.EDITOR.xpos",                   "7"                             },
+  { "bdx_stonefly.down.EDITOR.ypos",                   "1"                             },
+
+  { "bdx_biter",                                       "RocksBD.png"                   },
+  { "bdx_biter.xpos",                                  "0"                             },
+  { "bdx_biter.ypos",                                  "2"                             },
+  { "bdx_biter.frames",                                        "4"                             },
+  { "bdx_biter.anim_mode",                             "pingpong2"                     },
+  { "bdx_biter.left",                                  "RocksBD.png"                   },
+  { "bdx_biter.left.xpos",                             "0"                             },
+  { "bdx_biter.left.ypos",                             "2"                             },
+  { "bdx_biter.left.frames",                           "4"                             },
+  { "bdx_biter.left.anim_mode",                                "pingpong2"                     },
+  { "bdx_biter.left.EDITOR",                           "RocksBD.png"                   },
+  { "bdx_biter.left.EDITOR.xpos",                      "6"                             },
+  { "bdx_biter.left.EDITOR.ypos",                      "2"                             },
+  { "bdx_biter.right",                                 "RocksBD.png"                   },
+  { "bdx_biter.right.xpos",                            "0"                             },
+  { "bdx_biter.right.ypos",                            "2"                             },
+  { "bdx_biter.right.frames",                          "4"                             },
+  { "bdx_biter.right.anim_mode",                       "pingpong2"                     },
+  { "bdx_biter.right.EDITOR",                          "RocksBD.png"                   },
+  { "bdx_biter.right.EDITOR.xpos",                     "7"                             },
+  { "bdx_biter.right.EDITOR.ypos",                     "2"                             },
+  { "bdx_biter.up",                                    "RocksBD.png"                   },
+  { "bdx_biter.up.xpos",                               "0"                             },
+  { "bdx_biter.up.ypos",                               "2"                             },
+  { "bdx_biter.up.frames",                             "4"                             },
+  { "bdx_biter.up.anim_mode",                          "pingpong2"                     },
+  { "bdx_biter.up.EDITOR",                             "RocksBD.png"                   },
+  { "bdx_biter.up.EDITOR.xpos",                                "4"                             },
+  { "bdx_biter.up.EDITOR.ypos",                                "2"                             },
+  { "bdx_biter.down",                                  "RocksBD.png"                   },
+  { "bdx_biter.down.xpos",                             "0"                             },
+  { "bdx_biter.down.ypos",                             "2"                             },
+  { "bdx_biter.down.frames",                           "4"                             },
+  { "bdx_biter.down.anim_mode",                                "pingpong2"                     },
+  { "bdx_biter.down.EDITOR",                           "RocksBD.png"                   },
+  { "bdx_biter.down.EDITOR.xpos",                      "5"                             },
+  { "bdx_biter.down.EDITOR.ypos",                      "2"                             },
+  { "bdx_biter.moving",                                        "RocksBD.png"                   },
+  { "bdx_biter.moving.xpos",                           "0"                             },
+  { "bdx_biter.moving.ypos",                           "2"                             },
+  { "bdx_biter.moving.frames",                         "1"                             },
+
+  { "bdx_dragonfly",                                   "RocksBD.png"                   },
+  { "bdx_dragonfly.xpos",                              "2"                             },
+  { "bdx_dragonfly.ypos",                              "1"                             },
+  { "bdx_dragonfly.frames",                            "2"                             },
+  { "bdx_dragonfly.anim_mode",                         "pingpong"                      },
+  { "bdx_dragonfly.delay",                             "4"                             },
+  { "bdx_dragonfly.global_sync",                       "true"                          },
+  { "bdx_dragonfly.right",                             "RocksBD.png"                   },
+  { "bdx_dragonfly.right.xpos",                                "2"                             },
+  { "bdx_dragonfly.right.ypos",                                "1"                             },
+  { "bdx_dragonfly.right.frames",                      "2"                             },
+  { "bdx_dragonfly.right.anim_mode",                   "pingpong"                      },
+  { "bdx_dragonfly.right.delay",                       "4"                             },
+  { "bdx_dragonfly.right.global_sync",                 "true"                          },
+  { "bdx_dragonfly.right.EDITOR",                      "RocksBD.png"                   },
+  { "bdx_dragonfly.right.EDITOR.xpos",                 "8"                             },
+  { "bdx_dragonfly.right.EDITOR.ypos",                 "1"                             },
+  { "bdx_dragonfly.up",                                        "RocksBD.png"                   },
+  { "bdx_dragonfly.up.xpos",                           "2"                             },
+  { "bdx_dragonfly.up.ypos",                           "1"                             },
+  { "bdx_dragonfly.up.frames",                         "2"                             },
+  { "bdx_dragonfly.up.anim_mode",                      "pingpong"                      },
+  { "bdx_dragonfly.up.delay",                          "4"                             },
+  { "bdx_dragonfly.up.global_sync",                    "true"                          },
+  { "bdx_dragonfly.up.EDITOR",                         "RocksBD.png"                   },
+  { "bdx_dragonfly.up.EDITOR.xpos",                    "9"                             },
+  { "bdx_dragonfly.up.EDITOR.ypos",                    "1"                             },
+  { "bdx_dragonfly.left",                              "RocksBD.png"                   },
+  { "bdx_dragonfly.left.xpos",                         "2"                             },
+  { "bdx_dragonfly.left.ypos",                         "1"                             },
+  { "bdx_dragonfly.left.frames",                       "2"                             },
+  { "bdx_dragonfly.left.anim_mode",                    "pingpong"                      },
+  { "bdx_dragonfly.left.delay",                                "4"                             },
+  { "bdx_dragonfly.left.global_sync",                  "true"                          },
+  { "bdx_dragonfly.left.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_dragonfly.left.EDITOR.xpos",                  "10"                            },
+  { "bdx_dragonfly.left.EDITOR.ypos",                  "1"                             },
+  { "bdx_dragonfly.down",                              "RocksBD.png"                   },
+  { "bdx_dragonfly.down.xpos",                         "2"                             },
+  { "bdx_dragonfly.down.ypos",                         "1"                             },
+  { "bdx_dragonfly.down.frames",                       "2"                             },
+  { "bdx_dragonfly.down.anim_mode",                    "pingpong"                      },
+  { "bdx_dragonfly.down.delay",                                "4"                             },
+  { "bdx_dragonfly.down.global_sync",                  "true"                          },
+  { "bdx_dragonfly.down.EDITOR",                       "RocksBD.png"                   },
+  { "bdx_dragonfly.down.EDITOR.xpos",                  "11"                            },
+  { "bdx_dragonfly.down.EDITOR.ypos",                  "1"                             },
+
+  { "bdx_bomb",                                                "RocksBD.png"                   },
+  { "bdx_bomb.xpos",                                   "0"                             },
+  { "bdx_bomb.ypos",                                   "7"                             },
+  { "bdx_bomb.frames",                                 "1"                             },
+  { "bdx_bomb.active",                                 "RocksBD.png"                   },
+  { "bdx_bomb.active.xpos",                            "1"                             },
+  { "bdx_bomb.active.ypos",                            "7"                             },
+  { "bdx_bomb.active.frames",                          "7"                             },
+  { "bdx_bomb.active.delay",                           "8"                             },
+  { "bdx_bomb.active.anim_mode",                       "linear"                        },
+
+  { "bdx_rocket_launcher",                             "RocksBD.png"                   },
+  { "bdx_rocket_launcher.xpos",                                "9"                             },
+  { "bdx_rocket_launcher.ypos",                                "7"                             },
+  { "bdx_rocket_launcher.frames",                      "1"                             },
+
+  { "bdx_rocket",                                      "RocksBD.png"                   },
+  { "bdx_rocket.xpos",                                 "9"                             },
+  { "bdx_rocket.ypos",                                 "6"                             },
+  { "bdx_rocket.frames",                               "1"                             },
+  { "bdx_rocket.right",                                        "RocksBD.png"                   },
+  { "bdx_rocket.right.xpos",                           "8"                             },
+  { "bdx_rocket.right.ypos",                           "6"                             },
+  { "bdx_rocket.right.frames",                         "1"                             },
+  { "bdx_rocket.up",                                   "RocksBD.png"                   },
+  { "bdx_rocket.up.xpos",                              "9"                             },
+  { "bdx_rocket.up.ypos",                              "6"                             },
+  { "bdx_rocket.up.frames",                            "1"                             },
+  { "bdx_rocket.left",                                 "RocksBD.png"                   },
+  { "bdx_rocket.left.xpos",                            "10"                            },
+  { "bdx_rocket.left.ypos",                            "6"                             },
+  { "bdx_rocket.left.frames",                          "1"                             },
+  { "bdx_rocket.down",                                 "RocksBD.png"                   },
+  { "bdx_rocket.down.xpos",                            "11"                            },
+  { "bdx_rocket.down.ypos",                            "6"                             },
+  { "bdx_rocket.down.frames",                          "1"                             },
+
+  { "bdx_nitro_pack",                                  "RocksBD.png"                   },
+  { "bdx_nitro_pack.xpos",                             "3"                             },
+  { "bdx_nitro_pack.ypos",                             "4"                             },
+  { "bdx_nitro_pack.frames",                           "1"                             },
+  { "bdx_nitro_pack.falling.EDITOR",                   "RocksBD2.png"                  },
+  { "bdx_nitro_pack.falling.EDITOR.xpos",              "7"                             },
+  { "bdx_nitro_pack.falling.EDITOR.ypos",              "2"                             },
+  { "bdx_nitro_pack.exploding.EDITOR",                 "RocksBD2.png"                  },
+  { "bdx_nitro_pack.exploding.EDITOR.xpos",            "6"                             },
+  { "bdx_nitro_pack.exploding.EDITOR.ypos",            "2"                             },
+
+  { "bdx_fake_bonus",                                  "RocksBD.png"                   },
+  { "bdx_fake_bonus.xpos",                             "0"                             },
+  { "bdx_fake_bonus.ypos",                             "8"                             },
+  { "bdx_fake_bonus.frames",                           "4"                             },
+  { "bdx_fake_bonus.delay",                            "2"                             },
+
+  { "bdx_covered",                                     "RocksBD.png"                   },
+  { "bdx_covered.xpos",                                        "8"                             },
+  { "bdx_covered.ypos",                                        "3"                             },
+  { "bdx_covered.frames",                              "8"                             },
+  { "bdx_covered.delay",                               "2"                             },
+  { "bdx_covered.vertical",                            "true"                          },
+  { "bdx_covered.offset",                              "2"                             },
 
   // images for Supaplex style elements and actions
 
-  { "[sp_default].exploding",                  "RocksSP.png"           },
-  { "[sp_default].exploding.xpos",             "8"                     },
-  { "[sp_default].exploding.ypos",             "3"                     },
-  { "[sp_default].exploding.frames",           "8"                     },
-  { "[sp_default].exploding.delay",            "4"                     },
-  { "[sp_default].exploding.anim_mode",                "linear"                },
-
-  { "sp_zonk",                                 "RocksSP.png"           },
-  { "sp_zonk.xpos",                            "1"                     },
-  { "sp_zonk.ypos",                            "0"                     },
-  { "sp_zonk.frames",                          "1"                     },
-  { "sp_zonk.moving.left",                     "RocksSP.png"           },
-  { "sp_zonk.moving.left.xpos",                        "0"                     },
-  { "sp_zonk.moving.left.ypos",                        "6"                     },
-  { "sp_zonk.moving.left.frames",              "4"                     },
-  { "sp_zonk.moving.left.delay",               "1"                     },
-  { "sp_zonk.moving.left.anim_mode",           "reverse"               },
-  { "sp_zonk.moving.right",                    "RocksSP.png"           },
-  { "sp_zonk.moving.right.xpos",               "0"                     },
-  { "sp_zonk.moving.right.ypos",               "6"                     },
-  { "sp_zonk.moving.right.frames",             "4"                     },
-  { "sp_zonk.moving.right.start_frame",                "1"                     },
-  { "sp_zonk.moving.right.delay",              "1"                     },
-  { "sp_zonk.pushing.left",                    "RocksSP.png"           },
-  { "sp_zonk.pushing.left.xpos",               "0"                     },
-  { "sp_zonk.pushing.left.ypos",               "6"                     },
-  { "sp_zonk.pushing.left.frames",             "4"                     },
-  { "sp_zonk.pushing.left.delay",              "1"                     },
-  { "sp_zonk.pushing.left.anim_mode",          "reverse"               },
-  { "sp_zonk.pushing.right",                   "RocksSP.png"           },
-  { "sp_zonk.pushing.right.xpos",              "0"                     },
-  { "sp_zonk.pushing.right.ypos",              "6"                     },
-  { "sp_zonk.pushing.right.frames",            "4"                     },
-  { "sp_zonk.pushing.right.start_frame",       "1"                     },
-  { "sp_zonk.pushing.right.delay",             "1"                     },
-
-  { "sp_base",                                 "RocksSP.png"           },
-  { "sp_base.xpos",                            "2"                     },
-  { "sp_base.ypos",                            "0"                     },
-  { "sp_base.frames",                          "1"                     },
-  { "sp_base.digging",                         "RocksSP.png"           },
-  { "sp_base.digging.xpos",                    "2"                     },
-  { "sp_base.digging.ypos",                    "0"                     },
-  { "sp_base.digging.frames",                  "1"                     },
-  { "sp_base.digging.anim_mode",               "opaque_player"         },
-  { "sp_base.snapping",                                "RocksSP.png"           },
-  { "sp_base.snapping.xpos",                   "8"                     },
-  { "sp_base.snapping.ypos",                   "2"                     },
-  { "sp_base.snapping.frames",                 "7"                     },
-  { "sp_base.snapping.anim_mode",              "linear"                },
-
-  { "sp_murphy",                               "RocksSP.png"           },
-  { "sp_murphy.xpos",                          "3"                     },
-  { "sp_murphy.ypos",                          "0"                     },
-  { "sp_murphy.frames",                                "1"                     },
-  { "sp_murphy.moving.left",                   "RocksSP.png"           },
-  { "sp_murphy.moving.left.xpos",              "8"                     },
-  { "sp_murphy.moving.left.ypos",              "0"                     },
-  { "sp_murphy.moving.left.frames",            "3"                     },
-  { "sp_murphy.moving.left.anim_mode",         "pingpong"              },
-  { "sp_murphy.moving.left.delay",             "2"                     },
-  { "sp_murphy.moving.left.start_frame",       "1"                     },
-  { "sp_murphy.moving.right",                  "RocksSP.png"           },
-  { "sp_murphy.moving.right.xpos",             "11"                    },
-  { "sp_murphy.moving.right.ypos",             "0"                     },
-  { "sp_murphy.moving.right.frames",           "3"                     },
-  { "sp_murphy.moving.right.anim_mode",                "pingpong"              },
-  { "sp_murphy.moving.right.delay",            "2"                     },
-  { "sp_murphy.moving.right.start_frame",      "1"                     },
-  { "sp_murphy.digging.left",                  "RocksSP.png"           },
-  { "sp_murphy.digging.left.xpos",             "8"                     },
-  { "sp_murphy.digging.left.ypos",             "0"                     },
-  { "sp_murphy.digging.left.frames",           "3"                     },
-  { "sp_murphy.digging.left.anim_mode",                "pingpong"              },
-  { "sp_murphy.digging.left.delay",            "2"                     },
-  { "sp_murphy.digging.left.start_frame",      "1"                     },
-  { "sp_murphy.digging.right",                 "RocksSP.png"           },
-  { "sp_murphy.digging.right.xpos",            "11"                    },
-  { "sp_murphy.digging.right.ypos",            "0"                     },
-  { "sp_murphy.digging.right.frames",          "3"                     },
-  { "sp_murphy.digging.right.anim_mode",       "pingpong"              },
-  { "sp_murphy.digging.right.delay",           "2"                     },
-  { "sp_murphy.digging.right.start_frame",     "1"                     },
-  { "sp_murphy.collecting.left",               "RocksSP.png"           },
-  { "sp_murphy.collecting.left.xpos",          "8"                     },
-  { "sp_murphy.collecting.left.ypos",          "0"                     },
-  { "sp_murphy.collecting.left.frames",                "3"                     },
-  { "sp_murphy.collecting.left.anim_mode",     "pingpong"              },
-  { "sp_murphy.collecting.left.delay",         "2"                     },
-  { "sp_murphy.collecting.left.start_frame",   "1"                     },
-  { "sp_murphy.collecting.right",              "RocksSP.png"           },
-  { "sp_murphy.collecting.right.xpos",         "11"                    },
-  { "sp_murphy.collecting.right.ypos",         "0"                     },
-  { "sp_murphy.collecting.right.frames",       "3"                     },
-  { "sp_murphy.collecting.right.anim_mode",    "pingpong"              },
-  { "sp_murphy.collecting.right.delay",                "2"                     },
-  { "sp_murphy.collecting.right.start_frame",  "1"                     },
-  { "sp_murphy.pushing.left",                  "RocksSP.png"           },
-  { "sp_murphy.pushing.left.xpos",             "11"                    },
-  { "sp_murphy.pushing.left.ypos",             "1"                     },
-  { "sp_murphy.pushing.left.frames",           "1"                     },
-  { "sp_murphy.pushing.right",                 "RocksSP.png"           },
-  { "sp_murphy.pushing.right.xpos",            "10"                    },
-  { "sp_murphy.pushing.right.ypos",            "1"                     },
-  { "sp_murphy.pushing.right.frames",          "1"                     },
-  { "sp_murphy.snapping.left",                 "RocksSP.png"           },
-  { "sp_murphy.snapping.left.xpos",            "9"                     },
-  { "sp_murphy.snapping.left.ypos",            "1"                     },
-  { "sp_murphy.snapping.left.frames",          "1"                     },
-  { "sp_murphy.snapping.right",                        "RocksSP.png"           },
-  { "sp_murphy.snapping.right.xpos",           "8"                     },
-  { "sp_murphy.snapping.right.ypos",           "1"                     },
-  { "sp_murphy.snapping.right.frames",         "1"                     },
-  { "sp_murphy.snapping.up",                   "RocksSP.png"           },
-  { "sp_murphy.snapping.up.xpos",              "14"                    },
-  { "sp_murphy.snapping.up.ypos",              "0"                     },
-  { "sp_murphy.snapping.up.frames",            "1"                     },
-  { "sp_murphy.snapping.down",                 "RocksSP.png"           },
-  { "sp_murphy.snapping.down.xpos",            "15"                    },
-  { "sp_murphy.snapping.down.ypos",            "0"                     },
-  { "sp_murphy.snapping.down.frames",          "1"                     },
-  { "sp_murphy.boring",                                "RocksSP.png"           },
-  { "sp_murphy.boring.xpos",                   "11"                    },
-  { "sp_murphy.boring.ypos",                   "12"                    },
-  { "sp_murphy.boring.frames",                 "1"                     },
-  { "sp_murphy.boring[1]",                     "RocksSP.png"           },
-  { "sp_murphy.boring[1].xpos",                        "0"                     },
-  { "sp_murphy.boring[1].ypos",                        "12"                    },
-  { "sp_murphy.boring[1].frames",              "12"                    },
-  { "sp_murphy.boring[1].delay",               "10"                    },
-  { "sp_murphy.boring[1].anim_mode",           "linear"                },
-  { "sp_murphy.boring[1].anim_delay_fixed",    "120"                   },
-  { "sp_murphy.boring[1].anim_delay_random",   "0"                     },
-  { "sp_murphy.boring[1].post_delay_fixed",    "500"                   },
-  { "sp_murphy.boring[1].post_delay_random",   "500"                   },
-  { "sp_murphy.sleeping.left",                 "RocksSP.png"           },
-  { "sp_murphy.sleeping.left.xpos",            "4"                     },
-  { "sp_murphy.sleeping.left.ypos",            "9"                     },
-  { "sp_murphy.sleeping.left.frames",          "3"                     },
-  { "sp_murphy.sleeping.left.delay",           "100"                   },
-  { "sp_murphy.sleeping.left.anim_mode",       "linear,reverse"        },
-  { "sp_murphy.sleeping.right",                        "RocksSP.png"           },
-  { "sp_murphy.sleeping.right.xpos",           "13"                    },
-  { "sp_murphy.sleeping.right.ypos",           "12"                    },
-  { "sp_murphy.sleeping.right.frames",         "3"                     },
-  { "sp_murphy.sleeping.right.delay",          "100"                   },
-  { "sp_murphy.sleeping.right.anim_mode",      "linear"                },
-  { "sp_murphy.dropping",                      "RocksSP.png"           },
-  { "sp_murphy.dropping.xpos",                 "11"                    },
-  { "sp_murphy.dropping.ypos",                 "12"                    },
-  { "sp_murphy.dropping.frames",               "1"                     },
-  { "sp_murphy.shrinking",                     "RocksSP.png"           },
-  { "sp_murphy.shrinking.xpos",                        "8"                     },
-  { "sp_murphy.shrinking.ypos",                        "14"                    },
-  { "sp_murphy.shrinking.frames",              "8"                     },
-  { "sp_murphy.shrinking.delay",               "4"                     },
-  { "sp_murphy.shrinking.anim_mode",           "linear"                },
-
-  { "sp_murphy_clone",                         "RocksSP.png"           },
-  { "sp_murphy_clone.xpos",                    "3"                     },
-  { "sp_murphy_clone.ypos",                    "0"                     },
-  { "sp_murphy_clone.frames",                  "1"                     },
-
-  { "sp_infotron",                             "RocksSP.png"           },
-  { "sp_infotron.xpos",                                "4"                     },
-  { "sp_infotron.ypos",                                "0"                     },
-  { "sp_infotron.frames",                      "1"                     },
-  { "sp_infotron.EDITOR",                      "RocksSP.png"           },
-  { "sp_infotron.EDITOR.xpos",                 "8"                     },
-  { "sp_infotron.EDITOR.ypos",                 "11"                    },
-  { "sp_infotron.moving.left",                 "RocksSP.png"           },
-  { "sp_infotron.moving.left.xpos",            "8"                     },
-  { "sp_infotron.moving.left.ypos",            "13"                    },
-  { "sp_infotron.moving.left.frames",          "8"                     },
-  { "sp_infotron.moving.right",                        "RocksSP.png"           },
-  { "sp_infotron.moving.right.xpos",           "8"                     },
-  { "sp_infotron.moving.right.ypos",           "13"                    },
-  { "sp_infotron.moving.right.frames",         "8"                     },
-  { "sp_infotron.moving.right.start_frame",    "6"                     },
-  { "sp_infotron.moving.right.anim_mode",      "reverse"               },
-  { "sp_infotron.collecting",                  "RocksSP.png"           },
-  { "sp_infotron.collecting.xpos",             "8"                     },
-  { "sp_infotron.collecting.ypos",             "7"                     },
-  { "sp_infotron.collecting.frames",           "8"                     },
-  { "sp_infotron.collecting.anim_mode",                "linear"                },
-
-  { "sp_chip_single",                          "RocksSP.png"           },
-  { "sp_chip_single.xpos",                     "5"                     },
-  { "sp_chip_single.ypos",                     "0"                     },
-  { "sp_chip_single.frames",                   "1"                     },
-  { "sp_chip_left",                            "RocksSP.png"           },
-  { "sp_chip_left.xpos",                       "2"                     },
-  { "sp_chip_left.ypos",                       "3"                     },
-  { "sp_chip_left.frames",                     "1"                     },
-  { "sp_chip_right",                           "RocksSP.png"           },
-  { "sp_chip_right.xpos",                      "3"                     },
-  { "sp_chip_right.ypos",                      "3"                     },
-  { "sp_chip_right.frames",                    "1"                     },
-  { "sp_chip_top",                             "RocksSP.png"           },
-  { "sp_chip_top.xpos",                                "6"                     },
-  { "sp_chip_top.ypos",                                "4"                     },
-  { "sp_chip_top.frames",                      "1"                     },
-  { "sp_chip_bottom",                          "RocksSP.png"           },
-  { "sp_chip_bottom.xpos",                     "7"                     },
-  { "sp_chip_bottom.ypos",                     "4"                     },
-  { "sp_chip_bottom.frames",                   "1"                     },
-
-  { "sp_hardware_gray",                                "RocksSP.png"           },
-  { "sp_hardware_gray.xpos",                   "6"                     },
-  { "sp_hardware_gray.ypos",                   "0"                     },
-  { "sp_hardware_gray.frames",                 "1"                     },
-  { "sp_hardware_green",                       "RocksSP.png"           },
-  { "sp_hardware_green.xpos",                  "5"                     },
-  { "sp_hardware_green.ypos",                  "3"                     },
-  { "sp_hardware_green.frames",                        "1"                     },
-  { "sp_hardware_blue",                                "RocksSP.png"           },
-  { "sp_hardware_blue.xpos",                   "6"                     },
-  { "sp_hardware_blue.ypos",                   "3"                     },
-  { "sp_hardware_blue.frames",                 "1"                     },
-  { "sp_hardware_red",                         "RocksSP.png"           },
-  { "sp_hardware_red.xpos",                    "7"                     },
-  { "sp_hardware_red.ypos",                    "3"                     },
-  { "sp_hardware_red.frames",                  "1"                     },
-  { "sp_hardware_yellow",                      "RocksSP.png"           },
-  { "sp_hardware_yellow.xpos",                 "0"                     },
-  { "sp_hardware_yellow.ypos",                 "4"                     },
-  { "sp_hardware_yellow.frames",               "1"                     },
-
-  { "sp_exit_closed",                          "RocksSP.png"           },
-  { "sp_exit_closed.xpos",                     "7"                     },
-  { "sp_exit_closed.ypos",                     "0"                     },
-  { "sp_exit_closed.frames",                   "1"                     },
-  { "sp_exit.opening",                         "RocksSP.png"           },
-  { "sp_exit.opening.xpos",                    "7"                     },
-  { "sp_exit.opening.ypos",                    "0"                     },
-  { "sp_exit.opening.frames",                  "1"                     },
-  { "sp_exit_open",                            "RocksSP.png"           },
-  { "sp_exit_open.xpos",                       "7"                     },
-  { "sp_exit_open.ypos",                       "0"                     },
-  { "sp_exit_open.frames",                     "1"                     },
-  { "sp_exit.closing",                         "RocksSP.png"           },
-  { "sp_exit.closing.xpos",                    "7"                     },
-  { "sp_exit.closing.ypos",                    "0"                     },
-  { "sp_exit.closing.frames",                  "1"                     },
-
-  { "sp_disk_orange",                          "RocksSP.png"           },
-  { "sp_disk_orange.xpos",                     "0"                     },
-  { "sp_disk_orange.ypos",                     "1"                     },
-  { "sp_disk_orange.frames",                   "1"                     },
-
-  { "sp_disk_yellow",                          "RocksSP.png"           },
-  { "sp_disk_yellow.xpos",                     "2"                     },
-  { "sp_disk_yellow.ypos",                     "2"                     },
-  { "sp_disk_yellow.frames",                   "1"                     },
-
-  { "sp_disk_red",                             "RocksSP.png"           },
-  { "sp_disk_red.xpos",                                "4"                     },
-  { "sp_disk_red.ypos",                                "2"                     },
-  { "sp_disk_red.frames",                      "1"                     },
-  { "sp_disk_red.collecting",                  "RocksSP.png"           },
-  { "sp_disk_red.collecting.xpos",             "9"                     },
-  { "sp_disk_red.collecting.ypos",             "5"                     },
-  { "sp_disk_red.collecting.frames",           "7"                     },
-  { "sp_disk_red.collecting.anim_mode",                "linear"                },
-  { "sp_disk_red.active",                      "RocksSP.png"           },
-  { "sp_disk_red.active.xpos",                 "4"                     },
-  { "sp_disk_red.active.ypos",                 "2"                     },
-  { "sp_disk_red.active.frames",               "1"                     },
-
-  { "sp_port_right",                           "RocksSP.png"           },
-  { "sp_port_right.xpos",                      "1"                     },
-  { "sp_port_right.ypos",                      "1"                     },
-  { "sp_port_right.frames",                    "1"                     },
-  { "sp_port_down",                            "RocksSP.png"           },
-  { "sp_port_down.xpos",                       "2"                     },
-  { "sp_port_down.ypos",                       "1"                     },
-  { "sp_port_down.frames",                     "1"                     },
-  { "sp_port_left",                            "RocksSP.png"           },
-  { "sp_port_left.xpos",                       "3"                     },
-  { "sp_port_left.ypos",                       "1"                     },
-  { "sp_port_left.frames",                     "1"                     },
-  { "sp_port_up",                              "RocksSP.png"           },
-  { "sp_port_up.xpos",                         "4"                     },
-  { "sp_port_up.ypos",                         "1"                     },
-  { "sp_port_up.frames",                       "1"                     },
-  { "sp_port_horizontal",                      "RocksSP.png"           },
-  { "sp_port_horizontal.xpos",                 "6"                     },
-  { "sp_port_horizontal.ypos",                 "2"                     },
-  { "sp_port_horizontal.frames",               "1"                     },
-  { "sp_port_vertical",                                "RocksSP.png"           },
-  { "sp_port_vertical.xpos",                   "5"                     },
-  { "sp_port_vertical.ypos",                   "2"                     },
-  { "sp_port_vertical.frames",                 "1"                     },
-  { "sp_port_any",                             "RocksSP.png"           },
-  { "sp_port_any.xpos",                                "7"                     },
-  { "sp_port_any.ypos",                                "2"                     },
-  { "sp_port_any.frames",                      "1"                     },
-  { "sp_gravity_port_right",                   "RocksSP.png"           },
-  { "sp_gravity_port_right.xpos",              "1"                     },
-  { "sp_gravity_port_right.ypos",              "1"                     },
-  { "sp_gravity_port_right.frames",            "1"                     },
-  { "sp_gravity_port_right.EDITOR",            "RocksSP.png"           },
-  { "sp_gravity_port_right.EDITOR.xpos",       "0"                     },
-  { "sp_gravity_port_right.EDITOR.ypos",       "14"                    },
-  { "sp_gravity_port_down",                    "RocksSP.png"           },
-  { "sp_gravity_port_down.xpos",               "2"                     },
-  { "sp_gravity_port_down.ypos",               "1"                     },
-  { "sp_gravity_port_down.frames",             "1"                     },
-  { "sp_gravity_port_down.EDITOR",             "RocksSP.png"           },
-  { "sp_gravity_port_down.EDITOR.xpos",                "1"                     },
-  { "sp_gravity_port_down.EDITOR.ypos",                "14"                    },
-  { "sp_gravity_port_left",                    "RocksSP.png"           },
-  { "sp_gravity_port_left.xpos",               "3"                     },
-  { "sp_gravity_port_left.ypos",               "1"                     },
-  { "sp_gravity_port_left.frames",             "1"                     },
-  { "sp_gravity_port_left.EDITOR",             "RocksSP.png"           },
-  { "sp_gravity_port_left.EDITOR.xpos",                "2"                     },
-  { "sp_gravity_port_left.EDITOR.ypos",                "14"                    },
-  { "sp_gravity_port_up",                      "RocksSP.png"           },
-  { "sp_gravity_port_up.xpos",                 "4"                     },
-  { "sp_gravity_port_up.ypos",                 "1"                     },
-  { "sp_gravity_port_up.frames",               "1"                     },
-  { "sp_gravity_port_up.EDITOR",               "RocksSP.png"           },
-  { "sp_gravity_port_up.EDITOR.xpos",          "3"                     },
-  { "sp_gravity_port_up.EDITOR.ypos",          "14"                    },
-  { "sp_gravity_on_port_right",                        "RocksSP.png"           },
-  { "sp_gravity_on_port_right.xpos",           "1"                     },
-  { "sp_gravity_on_port_right.ypos",           "1"                     },
-  { "sp_gravity_on_port_right.frames",         "1"                     },
-  { "sp_gravity_on_port_right.EDITOR",         "RocksSP.png"           },
-  { "sp_gravity_on_port_right.EDITOR.xpos",    "0"                     },
-  { "sp_gravity_on_port_right.EDITOR.ypos",    "13"                    },
-  { "sp_gravity_on_port_down",                 "RocksSP.png"           },
-  { "sp_gravity_on_port_down.xpos",            "2"                     },
-  { "sp_gravity_on_port_down.ypos",            "1"                     },
-  { "sp_gravity_on_port_down.frames",          "1"                     },
-  { "sp_gravity_on_port_down.EDITOR",          "RocksSP.png"           },
-  { "sp_gravity_on_port_down.EDITOR.xpos",     "1"                     },
-  { "sp_gravity_on_port_down.EDITOR.ypos",     "13"                    },
-  { "sp_gravity_on_port_left",                 "RocksSP.png"           },
-  { "sp_gravity_on_port_left.xpos",            "3"                     },
-  { "sp_gravity_on_port_left.ypos",            "1"                     },
-  { "sp_gravity_on_port_left.frames",          "1"                     },
-  { "sp_gravity_on_port_left.EDITOR",          "RocksSP.png"           },
-  { "sp_gravity_on_port_left.EDITOR.xpos",     "2"                     },
-  { "sp_gravity_on_port_left.EDITOR.ypos",     "13"                    },
-  { "sp_gravity_on_port_up",                   "RocksSP.png"           },
-  { "sp_gravity_on_port_up.xpos",              "4"                     },
-  { "sp_gravity_on_port_up.ypos",              "1"                     },
-  { "sp_gravity_on_port_up.frames",            "1"                     },
-  { "sp_gravity_on_port_up.EDITOR",            "RocksSP.png"           },
-  { "sp_gravity_on_port_up.EDITOR.xpos",       "3"                     },
-  { "sp_gravity_on_port_up.EDITOR.ypos",       "13"                    },
-  { "sp_gravity_off_port_right",               "RocksSP.png"           },
-  { "sp_gravity_off_port_right.xpos",          "1"                     },
-  { "sp_gravity_off_port_right.ypos",          "1"                     },
-  { "sp_gravity_off_port_right.frames",                "1"                     },
-  { "sp_gravity_off_port_right.EDITOR",                "RocksSP.png"           },
-  { "sp_gravity_off_port_right.EDITOR.xpos",   "4"                     },
-  { "sp_gravity_off_port_right.EDITOR.ypos",   "13"                    },
-  { "sp_gravity_off_port_down",                        "RocksSP.png"           },
-  { "sp_gravity_off_port_down.xpos",           "2"                     },
-  { "sp_gravity_off_port_down.ypos",           "1"                     },
-  { "sp_gravity_off_port_down.frames",         "1"                     },
-  { "sp_gravity_off_port_down.EDITOR",         "RocksSP.png"           },
-  { "sp_gravity_off_port_down.EDITOR.xpos",    "5"                     },
-  { "sp_gravity_off_port_down.EDITOR.ypos",    "13"                    },
-  { "sp_gravity_off_port_left",                        "RocksSP.png"           },
-  { "sp_gravity_off_port_left.xpos",           "3"                     },
-  { "sp_gravity_off_port_left.ypos",           "1"                     },
-  { "sp_gravity_off_port_left.frames",         "1"                     },
-  { "sp_gravity_off_port_left.EDITOR",         "RocksSP.png"           },
-  { "sp_gravity_off_port_left.EDITOR.xpos",    "6"                     },
-  { "sp_gravity_off_port_left.EDITOR.ypos",    "13"                    },
-  { "sp_gravity_off_port_up",                  "RocksSP.png"           },
-  { "sp_gravity_off_port_up.xpos",             "4"                     },
-  { "sp_gravity_off_port_up.ypos",             "1"                     },
-  { "sp_gravity_off_port_up.frames",           "1"                     },
-  { "sp_gravity_off_port_up.EDITOR",           "RocksSP.png"           },
-  { "sp_gravity_off_port_up.EDITOR.xpos",      "7"                     },
-  { "sp_gravity_off_port_up.EDITOR.ypos",      "13"                    },
-
-  { "sp_sniksnak",                             "RocksSP.png"           },
-  { "sp_sniksnak.xpos",                                "1"                     },
-  { "sp_sniksnak.ypos",                                "2"                     },
-  { "sp_sniksnak.frames",                      "1"                     },
-  { "sp_sniksnak.left",                                "RocksSP.png"           },
-  { "sp_sniksnak.left.xpos",                   "8"                     },
-  { "sp_sniksnak.left.ypos",                   "8"                     },
-  { "sp_sniksnak.left.frames",                 "4"                     },
-  { "sp_sniksnak.left.anim_mode",              "pingpong2"             },
-  { "sp_sniksnak.right",                       "RocksSP.png"           },
-  { "sp_sniksnak.right.xpos",                  "12"                    },
-  { "sp_sniksnak.right.ypos",                  "8"                     },
-  { "sp_sniksnak.right.frames",                        "4"                     },
-  { "sp_sniksnak.right.anim_mode",             "pingpong2"             },
-  { "sp_sniksnak.up",                          "RocksSP.png"           },
-  { "sp_sniksnak.up.xpos",                     "8"                     },
-  { "sp_sniksnak.up.ypos",                     "9"                     },
-  { "sp_sniksnak.up.frames",                   "4"                     },
-  { "sp_sniksnak.up.anim_mode",                        "pingpong2"             },
-  { "sp_sniksnak.down",                                "RocksSP.png"           },
-  { "sp_sniksnak.down.xpos",                   "12"                    },
-  { "sp_sniksnak.down.ypos",                   "9"                     },
-  { "sp_sniksnak.down.frames",                 "4"                     },
-  { "sp_sniksnak.down.anim_mode",              "pingpong2"             },
-  { "sp_sniksnak.turning_from_left.up",                "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_left.up.xpos",   "12"                    },
-  { "sp_sniksnak.turning_from_left.up.ypos",   "6"                     },
-  { "sp_sniksnak.turning_from_left.up.frames", "2"                     },
-  { "sp_sniksnak.turning_from_left.up.delay",  "4"                     },
-  { "sp_sniksnak.turning_from_left.up.offset", "1408"                  },
-  { "sp_sniksnak.turning_from_left.up.anim_mode","linear"              },
-  { "sp_sniksnak.turning_from_left.down",      "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_left.down.xpos", "13"                    },
-  { "sp_sniksnak.turning_from_left.down.ypos", "6"                     },
-  { "sp_sniksnak.turning_from_left.down.frames","2"                    },
-  { "sp_sniksnak.turning_from_left.down.delay",        "4"                     },
-  { "sp_sniksnak.turning_from_left.down.offset","1504"                 },
-  { "sp_sniksnak.turning_from_left.down.anim_mode","linear"            },
-  { "sp_sniksnak.turning_from_right.up",       "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_right.up.xpos",  "15"                    },
-  { "sp_sniksnak.turning_from_right.up.ypos",  "6"                     },
-  { "sp_sniksnak.turning_from_right.up.frames",        "2"                     },
-  { "sp_sniksnak.turning_from_right.up.delay", "4"                     },
-  { "sp_sniksnak.turning_from_right.up.offset",        "1312"                  },
-  { "sp_sniksnak.turning_from_right.up.anim_mode","linear"             },
-  { "sp_sniksnak.turning_from_right.down",     "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_right.down.xpos",        "14"                    },
-  { "sp_sniksnak.turning_from_right.down.ypos",        "6"                     },
-  { "sp_sniksnak.turning_from_right.down.frames","2"                   },
-  { "sp_sniksnak.turning_from_right.down.delay","4"                    },
-  { "sp_sniksnak.turning_from_right.down.offset","1472"                        },
-  { "sp_sniksnak.turning_from_right.down.anim_mode","linear"           },
-  { "sp_sniksnak.turning_from_up.left",                "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_up.left.xpos",   "12"                    },
-  { "sp_sniksnak.turning_from_up.left.ypos",   "6"                     },
-  { "sp_sniksnak.turning_from_up.left.frames", "2"                     },
-  { "sp_sniksnak.turning_from_up.left.delay",  "4"                     },
-  { "sp_sniksnak.turning_from_up.left.offset", "896"                   },
-  { "sp_sniksnak.turning_from_up.left.anim_mode","linear"              },
-  { "sp_sniksnak.turning_from_up.right",       "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_up.right.xpos",  "15"                    },
-  { "sp_sniksnak.turning_from_up.right.ypos",  "6"                     },
-  { "sp_sniksnak.turning_from_up.right.frames",        "2"                     },
-  { "sp_sniksnak.turning_from_up.right.delay", "4"                     },
-  { "sp_sniksnak.turning_from_up.right.offset",        "928"                   },
-  { "sp_sniksnak.turning_from_up.right.anim_mode","linear"             },
-  { "sp_sniksnak.turning_from_down.left",      "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_down.left.xpos", "13"                    },
-  { "sp_sniksnak.turning_from_down.left.ypos", "6"                     },
-  { "sp_sniksnak.turning_from_down.left.frames","2"                    },
-  { "sp_sniksnak.turning_from_down.left.delay",        "4"                     },
-  { "sp_sniksnak.turning_from_down.left.offset","864"                  },
-  { "sp_sniksnak.turning_from_down.left.anim_mode","linear"            },
-  { "sp_sniksnak.turning_from_down.right",     "RocksSP.png"           },
-  { "sp_sniksnak.turning_from_down.right.xpos",        "14"                    },
-  { "sp_sniksnak.turning_from_down.right.ypos",        "6"                     },
-  { "sp_sniksnak.turning_from_down.right.frames","2"                   },
-  { "sp_sniksnak.turning_from_down.right.delay","4"                    },
-  { "sp_sniksnak.turning_from_down.right.offset","960"                 },
-  { "sp_sniksnak.turning_from_down.right.anim_mode","linear"           },
-
-  { "sp_electron",                             "RocksSP.png"           },
-  { "sp_electron.xpos",                                "8"                     },
-  { "sp_electron.ypos",                                "10"                    },
-  { "sp_electron.frames",                      "8"                     },
-  { "sp_electron.delay",                       "4"                     },
-  { "sp_electron.global_sync",                 "true"                  },
-  { "sp_electron.EDITOR",                      "RocksSP.png"           },
-  { "sp_electron.EDITOR.xpos",                 "10"                    },
-  { "sp_electron.EDITOR.ypos",                 "11"                    },
-  { "sp_electron.exploding",                   "RocksSP.png"           },
-  { "sp_electron.exploding.xpos",              "8"                     },
-  { "sp_electron.exploding.ypos",              "4"                     },
-  { "sp_electron.exploding.frames",            "8"                     },
-  { "sp_electron.exploding.delay",             "4"                     },
-  { "sp_electron.exploding.anim_mode",         "linear"                },
-
-  { "sp_terminal",                             "RocksSP.png"           },
-  { "sp_terminal.xpos",                                "0"                     },
-  { "sp_terminal.ypos",                                "10"                    },
-  { "sp_terminal.frames",                      "7"                     },
-  { "sp_terminal.delay",                       "12"                    },
-  { "sp_terminal.EDITOR",                      "RocksSP.png"           },
-  { "sp_terminal.EDITOR.xpos",                 "9"                     },
-  { "sp_terminal.EDITOR.ypos",                 "11"                    },
-  { "sp_terminal.active",                      "RocksSP.png"           },
-  { "sp_terminal.active.xpos",                 "0"                     },
-  { "sp_terminal.active.ypos",                 "11"                    },
-  { "sp_terminal.active.frames",               "7"                     },
-  { "sp_terminal.active.delay",                        "4"                     },
-
-  { "sp_buggy_base",                           "RocksSP.png"           },
-  { "sp_buggy_base.xpos",                      "1"                     },
-  { "sp_buggy_base.ypos",                      "3"                     },
-  { "sp_buggy_base.frames",                    "1"                     },
-  { "sp_buggy_base.EDITOR",                    "RocksSP.png"           },
-  { "sp_buggy_base.EDITOR.xpos",               "9"                     },
-  { "sp_buggy_base.EDITOR.ypos",               "6"                     },
-  { "sp_buggy_base.activating",                        "RocksSP.png"           },
-  { "sp_buggy_base.activating.xpos",           "15"                    },
-  { "sp_buggy_base.activating.ypos",           "2"                     },
-  { "sp_buggy_base.activating.frames",         "1"                     },
-  { "sp_buggy_base.active",                    "RocksSP.png"           },
-  { "sp_buggy_base.active.xpos",               "8"                     },
-  { "sp_buggy_base.active.ypos",               "6"                     },
-  { "sp_buggy_base.active.frames",             "4"                     },
-  { "sp_buggy_base.active.delay",              "4"                     },
-  { "sp_buggy_base.active.anim_mode",          "pingpong"              },
-
-  { "sp_hardware_base_1",                      "RocksSP.png"           },
-  { "sp_hardware_base_1.xpos",                 "4"                     },
-  { "sp_hardware_base_1.ypos",                 "3"                     },
-  { "sp_hardware_base_1.frames",               "1"                     },
-  { "sp_hardware_base_2",                      "RocksSP.png"           },
-  { "sp_hardware_base_2.xpos",                 "1"                     },
-  { "sp_hardware_base_2.ypos",                 "4"                     },
-  { "sp_hardware_base_2.frames",               "1"                     },
-  { "sp_hardware_base_3",                      "RocksSP.png"           },
-  { "sp_hardware_base_3.xpos",                 "2"                     },
-  { "sp_hardware_base_3.ypos",                 "4"                     },
-  { "sp_hardware_base_3.frames",               "1"                     },
-  { "sp_hardware_base_4",                      "RocksSP.png"           },
-  { "sp_hardware_base_4.xpos",                 "3"                     },
-  { "sp_hardware_base_4.ypos",                 "4"                     },
-  { "sp_hardware_base_4.frames",               "1"                     },
-  { "sp_hardware_base_5",                      "RocksSP.png"           },
-  { "sp_hardware_base_5.xpos",                 "4"                     },
-  { "sp_hardware_base_5.ypos",                 "4"                     },
-  { "sp_hardware_base_5.frames",               "1"                     },
-  { "sp_hardware_base_6",                      "RocksSP.png"           },
-  { "sp_hardware_base_6.xpos",                 "5"                     },
-  { "sp_hardware_base_6.ypos",                 "4"                     },
-  { "sp_hardware_base_6.frames",               "1"                     },
+  { "[sp_default].exploding",                          "RocksSP.png"                   },
+  { "[sp_default].exploding.xpos",                     "8"                             },
+  { "[sp_default].exploding.ypos",                     "3"                             },
+  { "[sp_default].exploding.frames",                   "8"                             },
+  { "[sp_default].exploding.delay",                    "4"                             },
+  { "[sp_default].exploding.anim_mode",                        "linear"                        },
+
+  { "sp_zonk",                                         "RocksSP.png"                   },
+  { "sp_zonk.xpos",                                    "1"                             },
+  { "sp_zonk.ypos",                                    "0"                             },
+  { "sp_zonk.frames",                                  "1"                             },
+  { "sp_zonk.moving.left",                             "RocksSP.png"                   },
+  { "sp_zonk.moving.left.xpos",                                "0"                             },
+  { "sp_zonk.moving.left.ypos",                                "6"                             },
+  { "sp_zonk.moving.left.frames",                      "4"                             },
+  { "sp_zonk.moving.left.delay",                       "1"                             },
+  { "sp_zonk.moving.left.anim_mode",                   "reverse"                       },
+  { "sp_zonk.moving.right",                            "RocksSP.png"                   },
+  { "sp_zonk.moving.right.xpos",                       "0"                             },
+  { "sp_zonk.moving.right.ypos",                       "6"                             },
+  { "sp_zonk.moving.right.frames",                     "4"                             },
+  { "sp_zonk.moving.right.start_frame",                        "1"                             },
+  { "sp_zonk.moving.right.delay",                      "1"                             },
+  { "sp_zonk.pushing.left",                            "RocksSP.png"                   },
+  { "sp_zonk.pushing.left.xpos",                       "0"                             },
+  { "sp_zonk.pushing.left.ypos",                       "6"                             },
+  { "sp_zonk.pushing.left.frames",                     "4"                             },
+  { "sp_zonk.pushing.left.delay",                      "1"                             },
+  { "sp_zonk.pushing.left.anim_mode",                  "reverse"                       },
+  { "sp_zonk.pushing.right",                           "RocksSP.png"                   },
+  { "sp_zonk.pushing.right.xpos",                      "0"                             },
+  { "sp_zonk.pushing.right.ypos",                      "6"                             },
+  { "sp_zonk.pushing.right.frames",                    "4"                             },
+  { "sp_zonk.pushing.right.start_frame",               "1"                             },
+  { "sp_zonk.pushing.right.delay",                     "1"                             },
+
+  { "sp_base",                                         "RocksSP.png"                   },
+  { "sp_base.xpos",                                    "2"                             },
+  { "sp_base.ypos",                                    "0"                             },
+  { "sp_base.frames",                                  "1"                             },
+  { "sp_base.digging",                                 "RocksSP.png"                   },
+  { "sp_base.digging.xpos",                            "2"                             },
+  { "sp_base.digging.ypos",                            "0"                             },
+  { "sp_base.digging.frames",                          "1"                             },
+  { "sp_base.digging.anim_mode",                       "opaque_player"                 },
+  { "sp_base.snapping",                                        "RocksSP.png"                   },
+  { "sp_base.snapping.xpos",                           "8"                             },
+  { "sp_base.snapping.ypos",                           "2"                             },
+  { "sp_base.snapping.frames",                         "7"                             },
+  { "sp_base.snapping.anim_mode",                      "linear"                        },
+
+  { "sp_murphy",                                       "RocksSP.png"                   },
+  { "sp_murphy.xpos",                                  "3"                             },
+  { "sp_murphy.ypos",                                  "0"                             },
+  { "sp_murphy.frames",                                        "1"                             },
+  { "sp_murphy.moving.left",                           "RocksSP.png"                   },
+  { "sp_murphy.moving.left.xpos",                      "8"                             },
+  { "sp_murphy.moving.left.ypos",                      "0"                             },
+  { "sp_murphy.moving.left.frames",                    "3"                             },
+  { "sp_murphy.moving.left.anim_mode",                 "pingpong"                      },
+  { "sp_murphy.moving.left.delay",                     "2"                             },
+  { "sp_murphy.moving.left.start_frame",               "1"                             },
+  { "sp_murphy.moving.right",                          "RocksSP.png"                   },
+  { "sp_murphy.moving.right.xpos",                     "11"                            },
+  { "sp_murphy.moving.right.ypos",                     "0"                             },
+  { "sp_murphy.moving.right.frames",                   "3"                             },
+  { "sp_murphy.moving.right.anim_mode",                        "pingpong"                      },
+  { "sp_murphy.moving.right.delay",                    "2"                             },
+  { "sp_murphy.moving.right.start_frame",              "1"                             },
+  { "sp_murphy.digging.left",                          "RocksSP.png"                   },
+  { "sp_murphy.digging.left.xpos",                     "8"                             },
+  { "sp_murphy.digging.left.ypos",                     "0"                             },
+  { "sp_murphy.digging.left.frames",                   "3"                             },
+  { "sp_murphy.digging.left.anim_mode",                        "pingpong"                      },
+  { "sp_murphy.digging.left.delay",                    "2"                             },
+  { "sp_murphy.digging.left.start_frame",              "1"                             },
+  { "sp_murphy.digging.right",                         "RocksSP.png"                   },
+  { "sp_murphy.digging.right.xpos",                    "11"                            },
+  { "sp_murphy.digging.right.ypos",                    "0"                             },
+  { "sp_murphy.digging.right.frames",                  "3"                             },
+  { "sp_murphy.digging.right.anim_mode",               "pingpong"                      },
+  { "sp_murphy.digging.right.delay",                   "2"                             },
+  { "sp_murphy.digging.right.start_frame",             "1"                             },
+  { "sp_murphy.collecting.left",                       "RocksSP.png"                   },
+  { "sp_murphy.collecting.left.xpos",                  "8"                             },
+  { "sp_murphy.collecting.left.ypos",                  "0"                             },
+  { "sp_murphy.collecting.left.frames",                        "3"                             },
+  { "sp_murphy.collecting.left.anim_mode",             "pingpong"                      },
+  { "sp_murphy.collecting.left.delay",                 "2"                             },
+  { "sp_murphy.collecting.left.start_frame",           "1"                             },
+  { "sp_murphy.collecting.right",                      "RocksSP.png"                   },
+  { "sp_murphy.collecting.right.xpos",                 "11"                            },
+  { "sp_murphy.collecting.right.ypos",                 "0"                             },
+  { "sp_murphy.collecting.right.frames",               "3"                             },
+  { "sp_murphy.collecting.right.anim_mode",            "pingpong"                      },
+  { "sp_murphy.collecting.right.delay",                        "2"                             },
+  { "sp_murphy.collecting.right.start_frame",          "1"                             },
+  { "sp_murphy.pushing.left",                          "RocksSP.png"                   },
+  { "sp_murphy.pushing.left.xpos",                     "11"                            },
+  { "sp_murphy.pushing.left.ypos",                     "1"                             },
+  { "sp_murphy.pushing.left.frames",                   "1"                             },
+  { "sp_murphy.pushing.right",                         "RocksSP.png"                   },
+  { "sp_murphy.pushing.right.xpos",                    "10"                            },
+  { "sp_murphy.pushing.right.ypos",                    "1"                             },
+  { "sp_murphy.pushing.right.frames",                  "1"                             },
+  { "sp_murphy.snapping.left",                         "RocksSP.png"                   },
+  { "sp_murphy.snapping.left.xpos",                    "9"                             },
+  { "sp_murphy.snapping.left.ypos",                    "1"                             },
+  { "sp_murphy.snapping.left.frames",                  "1"                             },
+  { "sp_murphy.snapping.right",                                "RocksSP.png"                   },
+  { "sp_murphy.snapping.right.xpos",                   "8"                             },
+  { "sp_murphy.snapping.right.ypos",                   "1"                             },
+  { "sp_murphy.snapping.right.frames",                 "1"                             },
+  { "sp_murphy.snapping.up",                           "RocksSP.png"                   },
+  { "sp_murphy.snapping.up.xpos",                      "14"                            },
+  { "sp_murphy.snapping.up.ypos",                      "0"                             },
+  { "sp_murphy.snapping.up.frames",                    "1"                             },
+  { "sp_murphy.snapping.down",                         "RocksSP.png"                   },
+  { "sp_murphy.snapping.down.xpos",                    "15"                            },
+  { "sp_murphy.snapping.down.ypos",                    "0"                             },
+  { "sp_murphy.snapping.down.frames",                  "1"                             },
+  { "sp_murphy.boring",                                        "RocksSP.png"                   },
+  { "sp_murphy.boring.xpos",                           "11"                            },
+  { "sp_murphy.boring.ypos",                           "12"                            },
+  { "sp_murphy.boring.frames",                         "1"                             },
+  { "sp_murphy.boring[1]",                             "RocksSP.png"                   },
+  { "sp_murphy.boring[1].xpos",                                "0"                             },
+  { "sp_murphy.boring[1].ypos",                                "12"                            },
+  { "sp_murphy.boring[1].frames",                      "12"                            },
+  { "sp_murphy.boring[1].delay",                       "10"                            },
+  { "sp_murphy.boring[1].anim_mode",                   "linear"                        },
+  { "sp_murphy.boring[1].anim_delay_fixed",            "120"                           },
+  { "sp_murphy.boring[1].anim_delay_random",           "0"                             },
+  { "sp_murphy.boring[1].post_delay_fixed",            "500"                           },
+  { "sp_murphy.boring[1].post_delay_random",           "500"                           },
+  { "sp_murphy.sleeping.left",                         "RocksSP.png"                   },
+  { "sp_murphy.sleeping.left.xpos",                    "4"                             },
+  { "sp_murphy.sleeping.left.ypos",                    "9"                             },
+  { "sp_murphy.sleeping.left.frames",                  "3"                             },
+  { "sp_murphy.sleeping.left.delay",                   "100"                           },
+  { "sp_murphy.sleeping.left.anim_mode",               "linear,reverse"                },
+  { "sp_murphy.sleeping.right",                                "RocksSP.png"                   },
+  { "sp_murphy.sleeping.right.xpos",                   "13"                            },
+  { "sp_murphy.sleeping.right.ypos",                   "12"                            },
+  { "sp_murphy.sleeping.right.frames",                 "3"                             },
+  { "sp_murphy.sleeping.right.delay",                  "100"                           },
+  { "sp_murphy.sleeping.right.anim_mode",              "linear"                        },
+  { "sp_murphy.dropping",                              "RocksSP.png"                   },
+  { "sp_murphy.dropping.xpos",                         "11"                            },
+  { "sp_murphy.dropping.ypos",                         "12"                            },
+  { "sp_murphy.dropping.frames",                       "1"                             },
+  { "sp_murphy.shrinking",                             "RocksSP.png"                   },
+  { "sp_murphy.shrinking.xpos",                                "8"                             },
+  { "sp_murphy.shrinking.ypos",                                "14"                            },
+  { "sp_murphy.shrinking.frames",                      "8"                             },
+  { "sp_murphy.shrinking.delay",                       "4"                             },
+  { "sp_murphy.shrinking.anim_mode",                   "linear"                        },
+
+  { "sp_murphy_clone",                                 "RocksSP.png"                   },
+  { "sp_murphy_clone.xpos",                            "3"                             },
+  { "sp_murphy_clone.ypos",                            "0"                             },
+  { "sp_murphy_clone.frames",                          "1"                             },
+
+  { "sp_infotron",                                     "RocksSP.png"                   },
+  { "sp_infotron.xpos",                                        "4"                             },
+  { "sp_infotron.ypos",                                        "0"                             },
+  { "sp_infotron.frames",                              "1"                             },
+  { "sp_infotron.EDITOR",                              "RocksSP.png"                   },
+  { "sp_infotron.EDITOR.xpos",                         "8"                             },
+  { "sp_infotron.EDITOR.ypos",                         "11"                            },
+  { "sp_infotron.moving.left",                         "RocksSP.png"                   },
+  { "sp_infotron.moving.left.xpos",                    "8"                             },
+  { "sp_infotron.moving.left.ypos",                    "13"                            },
+  { "sp_infotron.moving.left.frames",                  "8"                             },
+  { "sp_infotron.moving.right",                                "RocksSP.png"                   },
+  { "sp_infotron.moving.right.xpos",                   "8"                             },
+  { "sp_infotron.moving.right.ypos",                   "13"                            },
+  { "sp_infotron.moving.right.frames",                 "8"                             },
+  { "sp_infotron.moving.right.start_frame",            "6"                             },
+  { "sp_infotron.moving.right.anim_mode",              "reverse"                       },
+  { "sp_infotron.collecting",                          "RocksSP.png"                   },
+  { "sp_infotron.collecting.xpos",                     "8"                             },
+  { "sp_infotron.collecting.ypos",                     "7"                             },
+  { "sp_infotron.collecting.frames",                   "8"                             },
+  { "sp_infotron.collecting.anim_mode",                        "linear"                        },
+
+  { "sp_chip_single",                                  "RocksSP.png"                   },
+  { "sp_chip_single.xpos",                             "5"                             },
+  { "sp_chip_single.ypos",                             "0"                             },
+  { "sp_chip_single.frames",                           "1"                             },
+  { "sp_chip_left",                                    "RocksSP.png"                   },
+  { "sp_chip_left.xpos",                               "2"                             },
+  { "sp_chip_left.ypos",                               "3"                             },
+  { "sp_chip_left.frames",                             "1"                             },
+  { "sp_chip_right",                                   "RocksSP.png"                   },
+  { "sp_chip_right.xpos",                              "3"                             },
+  { "sp_chip_right.ypos",                              "3"                             },
+  { "sp_chip_right.frames",                            "1"                             },
+  { "sp_chip_top",                                     "RocksSP.png"                   },
+  { "sp_chip_top.xpos",                                        "6"                             },
+  { "sp_chip_top.ypos",                                        "4"                             },
+  { "sp_chip_top.frames",                              "1"                             },
+  { "sp_chip_bottom",                                  "RocksSP.png"                   },
+  { "sp_chip_bottom.xpos",                             "7"                             },
+  { "sp_chip_bottom.ypos",                             "4"                             },
+  { "sp_chip_bottom.frames",                           "1"                             },
+
+  { "sp_hardware_gray",                                        "RocksSP.png"                   },
+  { "sp_hardware_gray.xpos",                           "6"                             },
+  { "sp_hardware_gray.ypos",                           "0"                             },
+  { "sp_hardware_gray.frames",                         "1"                             },
+  { "sp_hardware_green",                               "RocksSP.png"                   },
+  { "sp_hardware_green.xpos",                          "5"                             },
+  { "sp_hardware_green.ypos",                          "3"                             },
+  { "sp_hardware_green.frames",                                "1"                             },
+  { "sp_hardware_blue",                                        "RocksSP.png"                   },
+  { "sp_hardware_blue.xpos",                           "6"                             },
+  { "sp_hardware_blue.ypos",                           "3"                             },
+  { "sp_hardware_blue.frames",                         "1"                             },
+  { "sp_hardware_red",                                 "RocksSP.png"                   },
+  { "sp_hardware_red.xpos",                            "7"                             },
+  { "sp_hardware_red.ypos",                            "3"                             },
+  { "sp_hardware_red.frames",                          "1"                             },
+  { "sp_hardware_yellow",                              "RocksSP.png"                   },
+  { "sp_hardware_yellow.xpos",                         "0"                             },
+  { "sp_hardware_yellow.ypos",                         "4"                             },
+  { "sp_hardware_yellow.frames",                       "1"                             },
+
+  { "sp_exit_closed",                                  "RocksSP.png"                   },
+  { "sp_exit_closed.xpos",                             "7"                             },
+  { "sp_exit_closed.ypos",                             "0"                             },
+  { "sp_exit_closed.frames",                           "1"                             },
+  { "sp_exit.opening",                                 "RocksSP.png"                   },
+  { "sp_exit.opening.xpos",                            "7"                             },
+  { "sp_exit.opening.ypos",                            "0"                             },
+  { "sp_exit.opening.frames",                          "1"                             },
+  { "sp_exit_open",                                    "RocksSP.png"                   },
+  { "sp_exit_open.xpos",                               "7"                             },
+  { "sp_exit_open.ypos",                               "0"                             },
+  { "sp_exit_open.frames",                             "1"                             },
+  { "sp_exit.closing",                                 "RocksSP.png"                   },
+  { "sp_exit.closing.xpos",                            "7"                             },
+  { "sp_exit.closing.ypos",                            "0"                             },
+  { "sp_exit.closing.frames",                          "1"                             },
+
+  { "sp_disk_orange",                                  "RocksSP.png"                   },
+  { "sp_disk_orange.xpos",                             "0"                             },
+  { "sp_disk_orange.ypos",                             "1"                             },
+  { "sp_disk_orange.frames",                           "1"                             },
+
+  { "sp_disk_yellow",                                  "RocksSP.png"                   },
+  { "sp_disk_yellow.xpos",                             "2"                             },
+  { "sp_disk_yellow.ypos",                             "2"                             },
+  { "sp_disk_yellow.frames",                           "1"                             },
+
+  { "sp_disk_red",                                     "RocksSP.png"                   },
+  { "sp_disk_red.xpos",                                        "4"                             },
+  { "sp_disk_red.ypos",                                        "2"                             },
+  { "sp_disk_red.frames",                              "1"                             },
+  { "sp_disk_red.collecting",                          "RocksSP.png"                   },
+  { "sp_disk_red.collecting.xpos",                     "9"                             },
+  { "sp_disk_red.collecting.ypos",                     "5"                             },
+  { "sp_disk_red.collecting.frames",                   "7"                             },
+  { "sp_disk_red.collecting.anim_mode",                        "linear"                        },
+  { "sp_disk_red.active",                              "RocksSP.png"                   },
+  { "sp_disk_red.active.xpos",                         "4"                             },
+  { "sp_disk_red.active.ypos",                         "2"                             },
+  { "sp_disk_red.active.frames",                       "1"                             },
+
+  { "sp_port_right",                                   "RocksSP.png"                   },
+  { "sp_port_right.xpos",                              "1"                             },
+  { "sp_port_right.ypos",                              "1"                             },
+  { "sp_port_right.frames",                            "1"                             },
+  { "sp_port_down",                                    "RocksSP.png"                   },
+  { "sp_port_down.xpos",                               "2"                             },
+  { "sp_port_down.ypos",                               "1"                             },
+  { "sp_port_down.frames",                             "1"                             },
+  { "sp_port_left",                                    "RocksSP.png"                   },
+  { "sp_port_left.xpos",                               "3"                             },
+  { "sp_port_left.ypos",                               "1"                             },
+  { "sp_port_left.frames",                             "1"                             },
+  { "sp_port_up",                                      "RocksSP.png"                   },
+  { "sp_port_up.xpos",                                 "4"                             },
+  { "sp_port_up.ypos",                                 "1"                             },
+  { "sp_port_up.frames",                               "1"                             },
+  { "sp_port_horizontal",                              "RocksSP.png"                   },
+  { "sp_port_horizontal.xpos",                         "6"                             },
+  { "sp_port_horizontal.ypos",                         "2"                             },
+  { "sp_port_horizontal.frames",                       "1"                             },
+  { "sp_port_vertical",                                        "RocksSP.png"                   },
+  { "sp_port_vertical.xpos",                           "5"                             },
+  { "sp_port_vertical.ypos",                           "2"                             },
+  { "sp_port_vertical.frames",                         "1"                             },
+  { "sp_port_any",                                     "RocksSP.png"                   },
+  { "sp_port_any.xpos",                                        "7"                             },
+  { "sp_port_any.ypos",                                        "2"                             },
+  { "sp_port_any.frames",                              "1"                             },
+  { "sp_gravity_port_right",                           "RocksSP.png"                   },
+  { "sp_gravity_port_right.xpos",                      "1"                             },
+  { "sp_gravity_port_right.ypos",                      "1"                             },
+  { "sp_gravity_port_right.frames",                    "1"                             },
+  { "sp_gravity_port_right.EDITOR",                    "RocksSP.png"                   },
+  { "sp_gravity_port_right.EDITOR.xpos",               "0"                             },
+  { "sp_gravity_port_right.EDITOR.ypos",               "14"                            },
+  { "sp_gravity_port_down",                            "RocksSP.png"                   },
+  { "sp_gravity_port_down.xpos",                       "2"                             },
+  { "sp_gravity_port_down.ypos",                       "1"                             },
+  { "sp_gravity_port_down.frames",                     "1"                             },
+  { "sp_gravity_port_down.EDITOR",                     "RocksSP.png"                   },
+  { "sp_gravity_port_down.EDITOR.xpos",                        "1"                             },
+  { "sp_gravity_port_down.EDITOR.ypos",                        "14"                            },
+  { "sp_gravity_port_left",                            "RocksSP.png"                   },
+  { "sp_gravity_port_left.xpos",                       "3"                             },
+  { "sp_gravity_port_left.ypos",                       "1"                             },
+  { "sp_gravity_port_left.frames",                     "1"                             },
+  { "sp_gravity_port_left.EDITOR",                     "RocksSP.png"                   },
+  { "sp_gravity_port_left.EDITOR.xpos",                        "2"                             },
+  { "sp_gravity_port_left.EDITOR.ypos",                        "14"                            },
+  { "sp_gravity_port_up",                              "RocksSP.png"                   },
+  { "sp_gravity_port_up.xpos",                         "4"                             },
+  { "sp_gravity_port_up.ypos",                         "1"                             },
+  { "sp_gravity_port_up.frames",                       "1"                             },
+  { "sp_gravity_port_up.EDITOR",                       "RocksSP.png"                   },
+  { "sp_gravity_port_up.EDITOR.xpos",                  "3"                             },
+  { "sp_gravity_port_up.EDITOR.ypos",                  "14"                            },
+  { "sp_gravity_on_port_right",                                "RocksSP.png"                   },
+  { "sp_gravity_on_port_right.xpos",                   "1"                             },
+  { "sp_gravity_on_port_right.ypos",                   "1"                             },
+  { "sp_gravity_on_port_right.frames",                 "1"                             },
+  { "sp_gravity_on_port_right.EDITOR",                 "RocksSP.png"                   },
+  { "sp_gravity_on_port_right.EDITOR.xpos",            "0"                             },
+  { "sp_gravity_on_port_right.EDITOR.ypos",            "13"                            },
+  { "sp_gravity_on_port_down",                         "RocksSP.png"                   },
+  { "sp_gravity_on_port_down.xpos",                    "2"                             },
+  { "sp_gravity_on_port_down.ypos",                    "1"                             },
+  { "sp_gravity_on_port_down.frames",                  "1"                             },
+  { "sp_gravity_on_port_down.EDITOR",                  "RocksSP.png"                   },
+  { "sp_gravity_on_port_down.EDITOR.xpos",             "1"                             },
+  { "sp_gravity_on_port_down.EDITOR.ypos",             "13"                            },
+  { "sp_gravity_on_port_left",                         "RocksSP.png"                   },
+  { "sp_gravity_on_port_left.xpos",                    "3"                             },
+  { "sp_gravity_on_port_left.ypos",                    "1"                             },
+  { "sp_gravity_on_port_left.frames",                  "1"                             },
+  { "sp_gravity_on_port_left.EDITOR",                  "RocksSP.png"                   },
+  { "sp_gravity_on_port_left.EDITOR.xpos",             "2"                             },
+  { "sp_gravity_on_port_left.EDITOR.ypos",             "13"                            },
+  { "sp_gravity_on_port_up",                           "RocksSP.png"                   },
+  { "sp_gravity_on_port_up.xpos",                      "4"                             },
+  { "sp_gravity_on_port_up.ypos",                      "1"                             },
+  { "sp_gravity_on_port_up.frames",                    "1"                             },
+  { "sp_gravity_on_port_up.EDITOR",                    "RocksSP.png"                   },
+  { "sp_gravity_on_port_up.EDITOR.xpos",               "3"                             },
+  { "sp_gravity_on_port_up.EDITOR.ypos",               "13"                            },
+  { "sp_gravity_off_port_right",                       "RocksSP.png"                   },
+  { "sp_gravity_off_port_right.xpos",                  "1"                             },
+  { "sp_gravity_off_port_right.ypos",                  "1"                             },
+  { "sp_gravity_off_port_right.frames",                        "1"                             },
+  { "sp_gravity_off_port_right.EDITOR",                        "RocksSP.png"                   },
+  { "sp_gravity_off_port_right.EDITOR.xpos",           "4"                             },
+  { "sp_gravity_off_port_right.EDITOR.ypos",           "13"                            },
+  { "sp_gravity_off_port_down",                                "RocksSP.png"                   },
+  { "sp_gravity_off_port_down.xpos",                   "2"                             },
+  { "sp_gravity_off_port_down.ypos",                   "1"                             },
+  { "sp_gravity_off_port_down.frames",                 "1"                             },
+  { "sp_gravity_off_port_down.EDITOR",                 "RocksSP.png"                   },
+  { "sp_gravity_off_port_down.EDITOR.xpos",            "5"                             },
+  { "sp_gravity_off_port_down.EDITOR.ypos",            "13"                            },
+  { "sp_gravity_off_port_left",                                "RocksSP.png"                   },
+  { "sp_gravity_off_port_left.xpos",                   "3"                             },
+  { "sp_gravity_off_port_left.ypos",                   "1"                             },
+  { "sp_gravity_off_port_left.frames",                 "1"                             },
+  { "sp_gravity_off_port_left.EDITOR",                 "RocksSP.png"                   },
+  { "sp_gravity_off_port_left.EDITOR.xpos",            "6"                             },
+  { "sp_gravity_off_port_left.EDITOR.ypos",            "13"                            },
+  { "sp_gravity_off_port_up",                          "RocksSP.png"                   },
+  { "sp_gravity_off_port_up.xpos",                     "4"                             },
+  { "sp_gravity_off_port_up.ypos",                     "1"                             },
+  { "sp_gravity_off_port_up.frames",                   "1"                             },
+  { "sp_gravity_off_port_up.EDITOR",                   "RocksSP.png"                   },
+  { "sp_gravity_off_port_up.EDITOR.xpos",              "7"                             },
+  { "sp_gravity_off_port_up.EDITOR.ypos",              "13"                            },
+
+  { "sp_sniksnak",                                     "RocksSP.png"                   },
+  { "sp_sniksnak.xpos",                                        "1"                             },
+  { "sp_sniksnak.ypos",                                        "2"                             },
+  { "sp_sniksnak.frames",                              "1"                             },
+  { "sp_sniksnak.left",                                        "RocksSP.png"                   },
+  { "sp_sniksnak.left.xpos",                           "8"                             },
+  { "sp_sniksnak.left.ypos",                           "8"                             },
+  { "sp_sniksnak.left.frames",                         "4"                             },
+  { "sp_sniksnak.left.anim_mode",                      "pingpong2"                     },
+  { "sp_sniksnak.right",                               "RocksSP.png"                   },
+  { "sp_sniksnak.right.xpos",                          "12"                            },
+  { "sp_sniksnak.right.ypos",                          "8"                             },
+  { "sp_sniksnak.right.frames",                                "4"                             },
+  { "sp_sniksnak.right.anim_mode",                     "pingpong2"                     },
+  { "sp_sniksnak.up",                                  "RocksSP.png"                   },
+  { "sp_sniksnak.up.xpos",                             "8"                             },
+  { "sp_sniksnak.up.ypos",                             "9"                             },
+  { "sp_sniksnak.up.frames",                           "4"                             },
+  { "sp_sniksnak.up.anim_mode",                                "pingpong2"                     },
+  { "sp_sniksnak.down",                                        "RocksSP.png"                   },
+  { "sp_sniksnak.down.xpos",                           "12"                            },
+  { "sp_sniksnak.down.ypos",                           "9"                             },
+  { "sp_sniksnak.down.frames",                         "4"                             },
+  { "sp_sniksnak.down.anim_mode",                      "pingpong2"                     },
+  { "sp_sniksnak.turning_from_left.up",                        "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_left.up.xpos",           "12"                            },
+  { "sp_sniksnak.turning_from_left.up.ypos",           "6"                             },
+  { "sp_sniksnak.turning_from_left.up.frames",         "2"                             },
+  { "sp_sniksnak.turning_from_left.up.delay",          "4"                             },
+  { "sp_sniksnak.turning_from_left.up.offset",         "1408"                          },
+  { "sp_sniksnak.turning_from_left.up.anim_mode",      "linear"                        },
+  { "sp_sniksnak.turning_from_left.down",              "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_left.down.xpos",         "13"                            },
+  { "sp_sniksnak.turning_from_left.down.ypos",         "6"                             },
+  { "sp_sniksnak.turning_from_left.down.frames",       "2"                             },
+  { "sp_sniksnak.turning_from_left.down.delay",                "4"                             },
+  { "sp_sniksnak.turning_from_left.down.offset",       "1504"                          },
+  { "sp_sniksnak.turning_from_left.down.anim_mode",    "linear"                        },
+  { "sp_sniksnak.turning_from_right.up",               "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_right.up.xpos",          "15"                            },
+  { "sp_sniksnak.turning_from_right.up.ypos",          "6"                             },
+  { "sp_sniksnak.turning_from_right.up.frames",                "2"                             },
+  { "sp_sniksnak.turning_from_right.up.delay",         "4"                             },
+  { "sp_sniksnak.turning_from_right.up.offset",                "1312"                          },
+  { "sp_sniksnak.turning_from_right.up.anim_mode",     "linear"                        },
+  { "sp_sniksnak.turning_from_right.down",             "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_right.down.xpos",                "14"                            },
+  { "sp_sniksnak.turning_from_right.down.ypos",                "6"                             },
+  { "sp_sniksnak.turning_from_right.down.frames",      "2"                             },
+  { "sp_sniksnak.turning_from_right.down.delay",       "4"                             },
+  { "sp_sniksnak.turning_from_right.down.offset",      "1472"                          },
+  { "sp_sniksnak.turning_from_right.down.anim_mode",   "linear"                        },
+  { "sp_sniksnak.turning_from_up.left",                        "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_up.left.xpos",           "12"                            },
+  { "sp_sniksnak.turning_from_up.left.ypos",           "6"                             },
+  { "sp_sniksnak.turning_from_up.left.frames",         "2"                             },
+  { "sp_sniksnak.turning_from_up.left.delay",          "4"                             },
+  { "sp_sniksnak.turning_from_up.left.offset",         "896"                           },
+  { "sp_sniksnak.turning_from_up.left.anim_mode",      "linear"                        },
+  { "sp_sniksnak.turning_from_up.right",               "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_up.right.xpos",          "15"                            },
+  { "sp_sniksnak.turning_from_up.right.ypos",          "6"                             },
+  { "sp_sniksnak.turning_from_up.right.frames",                "2"                             },
+  { "sp_sniksnak.turning_from_up.right.delay",         "4"                             },
+  { "sp_sniksnak.turning_from_up.right.offset",                "928"                           },
+  { "sp_sniksnak.turning_from_up.right.anim_mode",     "linear"                        },
+  { "sp_sniksnak.turning_from_down.left",              "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_down.left.xpos",         "13"                            },
+  { "sp_sniksnak.turning_from_down.left.ypos",         "6"                             },
+  { "sp_sniksnak.turning_from_down.left.frames",       "2"                             },
+  { "sp_sniksnak.turning_from_down.left.delay",                "4"                             },
+  { "sp_sniksnak.turning_from_down.left.offset",       "864"                           },
+  { "sp_sniksnak.turning_from_down.left.anim_mode",    "linear"                        },
+  { "sp_sniksnak.turning_from_down.right",             "RocksSP.png"                   },
+  { "sp_sniksnak.turning_from_down.right.xpos",                "14"                            },
+  { "sp_sniksnak.turning_from_down.right.ypos",                "6"                             },
+  { "sp_sniksnak.turning_from_down.right.frames",      "2"                             },
+  { "sp_sniksnak.turning_from_down.right.delay",       "4"                             },
+  { "sp_sniksnak.turning_from_down.right.offset",      "960"                           },
+  { "sp_sniksnak.turning_from_down.right.anim_mode",   "linear"                        },
+
+  { "sp_electron",                                     "RocksSP.png"                   },
+  { "sp_electron.xpos",                                        "8"                             },
+  { "sp_electron.ypos",                                        "10"                            },
+  { "sp_electron.frames",                              "8"                             },
+  { "sp_electron.delay",                               "4"                             },
+  { "sp_electron.global_sync",                         "true"                          },
+  { "sp_electron.EDITOR",                              "RocksSP.png"                   },
+  { "sp_electron.EDITOR.xpos",                         "10"                            },
+  { "sp_electron.EDITOR.ypos",                         "11"                            },
+  { "sp_electron.exploding",                           "RocksSP.png"                   },
+  { "sp_electron.exploding.xpos",                      "8"                             },
+  { "sp_electron.exploding.ypos",                      "4"                             },
+  { "sp_electron.exploding.frames",                    "8"                             },
+  { "sp_electron.exploding.delay",                     "4"                             },
+  { "sp_electron.exploding.anim_mode",                 "linear"                        },
+
+  { "sp_terminal",                                     "RocksSP.png"                   },
+  { "sp_terminal.xpos",                                        "0"                             },
+  { "sp_terminal.ypos",                                        "10"                            },
+  { "sp_terminal.frames",                              "7"                             },
+  { "sp_terminal.delay",                               "12"                            },
+  { "sp_terminal.EDITOR",                              "RocksSP.png"                   },
+  { "sp_terminal.EDITOR.xpos",                         "9"                             },
+  { "sp_terminal.EDITOR.ypos",                         "11"                            },
+  { "sp_terminal.active",                              "RocksSP.png"                   },
+  { "sp_terminal.active.xpos",                         "0"                             },
+  { "sp_terminal.active.ypos",                         "11"                            },
+  { "sp_terminal.active.frames",                       "7"                             },
+  { "sp_terminal.active.delay",                                "4"                             },
+
+  { "sp_buggy_base",                                   "RocksSP.png"                   },
+  { "sp_buggy_base.xpos",                              "1"                             },
+  { "sp_buggy_base.ypos",                              "3"                             },
+  { "sp_buggy_base.frames",                            "1"                             },
+  { "sp_buggy_base.EDITOR",                            "RocksSP.png"                   },
+  { "sp_buggy_base.EDITOR.xpos",                       "9"                             },
+  { "sp_buggy_base.EDITOR.ypos",                       "6"                             },
+  { "sp_buggy_base.activating",                                "RocksSP.png"                   },
+  { "sp_buggy_base.activating.xpos",                   "15"                            },
+  { "sp_buggy_base.activating.ypos",                   "2"                             },
+  { "sp_buggy_base.activating.frames",                 "1"                             },
+  { "sp_buggy_base.active",                            "RocksSP.png"                   },
+  { "sp_buggy_base.active.xpos",                       "8"                             },
+  { "sp_buggy_base.active.ypos",                       "6"                             },
+  { "sp_buggy_base.active.frames",                     "4"                             },
+  { "sp_buggy_base.active.delay",                      "4"                             },
+  { "sp_buggy_base.active.anim_mode",                  "pingpong"                      },
+
+  { "sp_hardware_base_1",                              "RocksSP.png"                   },
+  { "sp_hardware_base_1.xpos",                         "4"                             },
+  { "sp_hardware_base_1.ypos",                         "3"                             },
+  { "sp_hardware_base_1.frames",                       "1"                             },
+  { "sp_hardware_base_2",                              "RocksSP.png"                   },
+  { "sp_hardware_base_2.xpos",                         "1"                             },
+  { "sp_hardware_base_2.ypos",                         "4"                             },
+  { "sp_hardware_base_2.frames",                       "1"                             },
+  { "sp_hardware_base_3",                              "RocksSP.png"                   },
+  { "sp_hardware_base_3.xpos",                         "2"                             },
+  { "sp_hardware_base_3.ypos",                         "4"                             },
+  { "sp_hardware_base_3.frames",                       "1"                             },
+  { "sp_hardware_base_4",                              "RocksSP.png"                   },
+  { "sp_hardware_base_4.xpos",                         "3"                             },
+  { "sp_hardware_base_4.ypos",                         "4"                             },
+  { "sp_hardware_base_4.frames",                       "1"                             },
+  { "sp_hardware_base_5",                              "RocksSP.png"                   },
+  { "sp_hardware_base_5.xpos",                         "4"                             },
+  { "sp_hardware_base_5.ypos",                         "4"                             },
+  { "sp_hardware_base_5.frames",                       "1"                             },
+  { "sp_hardware_base_6",                              "RocksSP.png"                   },
+  { "sp_hardware_base_6.xpos",                         "5"                             },
+  { "sp_hardware_base_6.ypos",                         "4"                             },
+  { "sp_hardware_base_6.frames",                       "1"                             },
 
   // images for Sokoban style elements and actions
 
-  { "sokoban_object",                          "RocksElements.png"     },
-  { "sokoban_object.xpos",                     "9"                     },
-  { "sokoban_object.ypos",                     "7"                     },
-  { "sokoban_object.frames",                   "1"                     },
+  { "sokoban_object",                                  "RocksElements.png"             },
+  { "sokoban_object.xpos",                             "9"                             },
+  { "sokoban_object.ypos",                             "7"                             },
+  { "sokoban_object.frames",                           "1"                             },
 
-  { "sokoban_field_empty",                     "RocksElements.png"     },
-  { "sokoban_field_empty.xpos",                        "10"                    },
-  { "sokoban_field_empty.ypos",                        "7"                     },
-  { "sokoban_field_empty.frames",              "1"                     },
+  { "sokoban_field_empty",                             "RocksElements.png"             },
+  { "sokoban_field_empty.xpos",                                "10"                            },
+  { "sokoban_field_empty.ypos",                                "7"                             },
+  { "sokoban_field_empty.frames",                      "1"                             },
 
-  { "sokoban_field_full",                      "RocksElements.png"     },
-  { "sokoban_field_full.xpos",                 "11"                    },
-  { "sokoban_field_full.ypos",                 "7"                     },
-  { "sokoban_field_full.frames",               "1"                     },
+  { "sokoban_field_full",                              "RocksElements.png"             },
+  { "sokoban_field_full.xpos",                         "11"                            },
+  { "sokoban_field_full.ypos",                         "7"                             },
+  { "sokoban_field_full.frames",                       "1"                             },
 
-  { "sokoban_field_player",                    "RocksHeroes.png"       },
-  { "sokoban_field_player.xpos",               "0"                     },
-  { "sokoban_field_player.ypos",               "15"                    },
-  { "sokoban_field_player.frames",             "1"                     },
+  { "sokoban_field_player",                            "RocksHeroes.png"               },
+  { "sokoban_field_player.xpos",                       "0"                             },
+  { "sokoban_field_player.ypos",                       "15"                            },
+  { "sokoban_field_player.frames",                     "1"                             },
 
   // images for Emerald Mine style elements and actions
 
-  { "empty_space",                             "RocksSP.png"           },
-  { "empty_space.xpos",                                "0"                     },
-  { "empty_space.ypos",                                "0"                     },
-  { "empty_space.frames",                      "1"                     },
-
-  { "sand",                                    "RocksElements.png"     },
-  { "sand.xpos",                               "0"                     },
-  { "sand.ypos",                               "0"                     },
-  { "sand.frames",                             "1"                     },
-  { "sand.CRUMBLED",                           "RocksElements.png"     },
-  { "sand.CRUMBLED.xpos",                      "1"                     },
-  { "sand.CRUMBLED.ypos",                      "0"                     },
-  { "sand.CRUMBLED.frames",                    "1"                     },
-  { "sand.digging.left",                       "RocksMore.png"         },
-  { "sand.digging.left.xpos",                  "6"                     },
-  { "sand.digging.left.ypos",                  "3"                     },
-  { "sand.digging.left.frames",                        "3"                     },
-  { "sand.digging.left.delay",                 "2"                     },
-  { "sand.digging.left.anim_mode",             "linear"                },
-  { "sand.digging.right",                      "RocksMore.png"         },
-  { "sand.digging.right.xpos",                 "9"                     },
-  { "sand.digging.right.ypos",                 "3"                     },
-  { "sand.digging.right.frames",               "3"                     },
-  { "sand.digging.right.delay",                        "2"                     },
-  { "sand.digging.right.anim_mode",            "linear"                },
-  { "sand.digging.up",                         "RocksMore.png"         },
-  { "sand.digging.up.xpos",                    "0"                     },
-  { "sand.digging.up.ypos",                    "3"                     },
-  { "sand.digging.up.frames",                  "3"                     },
-  { "sand.digging.up.delay",                   "2"                     },
-  { "sand.digging.up.anim_mode",               "linear"                },
-  { "sand.digging.down",                       "RocksMore.png"         },
-  { "sand.digging.down.xpos",                  "3"                     },
-  { "sand.digging.down.ypos",                  "3"                     },
-  { "sand.digging.down.frames",                        "3"                     },
-  { "sand.digging.down.delay",                 "2"                     },
-  { "sand.digging.down.anim_mode",             "linear"                },
-  { "sand.digging.left.CRUMBLED",              "RocksMore.png"         },
-  { "sand.digging.left.CRUMBLED.xpos",         "6"                     },
-  { "sand.digging.left.CRUMBLED.ypos",         "0"                     },
-  { "sand.digging.left.CRUMBLED.frames",       "3"                     },
-  { "sand.digging.left.CRUMBLED.delay",                "2"                     },
-  { "sand.digging.left.CRUMBLED.anim_mode",    "linear"                },
-  { "sand.digging.right.CRUMBLED",             "RocksMore.png"         },
-  { "sand.digging.right.CRUMBLED.xpos",                "9"                     },
-  { "sand.digging.right.CRUMBLED.ypos",                "0"                     },
-  { "sand.digging.right.CRUMBLED.frames",      "3"                     },
-  { "sand.digging.right.CRUMBLED.delay",       "2"                     },
-  { "sand.digging.right.CRUMBLED.anim_mode",   "linear"                },
-  { "sand.digging.up.CRUMBLED",                        "RocksMore.png"         },
-  { "sand.digging.up.CRUMBLED.xpos",           "0"                     },
-  { "sand.digging.up.CRUMBLED.ypos",           "0"                     },
-  { "sand.digging.up.CRUMBLED.frames",         "3"                     },
-  { "sand.digging.up.CRUMBLED.delay",          "2"                     },
-  { "sand.digging.up.CRUMBLED.anim_mode",      "linear"                },
-  { "sand.digging.down.CRUMBLED",              "RocksMore.png"         },
-  { "sand.digging.down.CRUMBLED.xpos",         "3"                     },
-  { "sand.digging.down.CRUMBLED.ypos",         "0"                     },
-  { "sand.digging.down.CRUMBLED.frames",       "3"                     },
-  { "sand.digging.down.CRUMBLED.delay",                "2"                     },
-  { "sand.digging.down.CRUMBLED.anim_mode",    "linear"                },
-
-  { "wall",                                    "RocksElements.png"     },
-  { "wall.xpos",                               "5"                     },
-  { "wall.ypos",                               "0"                     },
-  { "wall.frames",                             "1"                     },
-
-  { "wall_slippery",                           "RocksElements.png"     },
-  { "wall_slippery.xpos",                      "6"                     },
-  { "wall_slippery.ypos",                      "0"                     },
-  { "wall_slippery.frames",                    "1"                     },
-
-  { "steelwall",                               "RocksElements.png"     },
-  { "steelwall.xpos",                          "4"                     },
-  { "steelwall.ypos",                          "0"                     },
-  { "steelwall.frames",                                "1"                     },
-
-  { "rock",                                    "RocksElements.png"     },
-  { "rock.xpos",                               "12"                    },
-  { "rock.ypos",                               "0"                     },
-  { "rock.frames",                             "1"                     },
-  { "rock.moving.left",                                "RocksElements.png"     },
-  { "rock.moving.left.xpos",                   "12"                    },
-  { "rock.moving.left.ypos",                   "0"                     },
-  { "rock.moving.left.frames",                 "4"                     },
-  { "rock.moving.left.delay",                  "2"                     },
-  { "rock.moving.left.anim_mode",              "reverse"               },
-  { "rock.moving.right",                       "RocksElements.png"     },
-  { "rock.moving.right.xpos",                  "12"                    },
-  { "rock.moving.right.ypos",                  "0"                     },
-  { "rock.moving.right.frames",                        "4"                     },
-  { "rock.moving.right.start_frame",           "1"                     },
-  { "rock.moving.right.delay",                 "2"                     },
-  { "rock.pushing.left",                       "RocksElements.png"     },
-  { "rock.pushing.left.xpos",                  "12"                    },
-  { "rock.pushing.left.ypos",                  "0"                     },
-  { "rock.pushing.left.frames",                        "4"                     },
-  { "rock.pushing.left.delay",                 "2"                     },
-  { "rock.pushing.left.anim_mode",             "reverse"               },
-  { "rock.pushing.right",                      "RocksElements.png"     },
-  { "rock.pushing.right.xpos",                 "12"                    },
-  { "rock.pushing.right.ypos",                 "0"                     },
-  { "rock.pushing.right.frames",               "4"                     },
-  { "rock.pushing.right.start_frame",          "1"                     },
-  { "rock.pushing.right.delay",                        "2"                     },
-
-  { "emerald",                                 "RocksElements.png"     },
-  { "emerald.xpos",                            "8"                     },
-  { "emerald.ypos",                            "0"                     },
-  { "emerald.frames",                          "1"                     },
-  { "emerald.moving",                          "RocksElements.png"     },
-  { "emerald.moving.xpos",                     "8"                     },
-  { "emerald.moving.ypos",                     "0"                     },
-  { "emerald.moving.frames",                   "2"                     },
-  { "emerald.moving.delay",                    "4"                     },
-  { "emerald.falling",                         "RocksElements.png"     },
-  { "emerald.falling.xpos",                    "8"                     },
-  { "emerald.falling.ypos",                    "0"                     },
-  { "emerald.falling.frames",                  "2"                     },
-  { "emerald.falling.delay",                   "4"                     },
-  { "emerald.collecting",                      "RocksCollect.png"      },
-  { "emerald.collecting.xpos",                 "0"                     },
-  { "emerald.collecting.ypos",                 "0"                     },
-  { "emerald.collecting.frames",               "7"                     },
-  { "emerald.collecting.anim_mode",            "linear"                },
-
-  { "diamond",                                 "RocksElements.png"     },
-  { "diamond.xpos",                            "10"                    },
-  { "diamond.ypos",                            "0"                     },
-  { "diamond.frames",                          "1"                     },
-  { "diamond.moving",                          "RocksElements.png"     },
-  { "diamond.moving.xpos",                     "10"                    },
-  { "diamond.moving.ypos",                     "0"                     },
-  { "diamond.moving.frames",                   "2"                     },
-  { "diamond.moving.delay",                    "4"                     },
-  { "diamond.falling",                         "RocksElements.png"     },
-  { "diamond.falling.xpos",                    "10"                    },
-  { "diamond.falling.ypos",                    "0"                     },
-  { "diamond.falling.frames",                  "2"                     },
-  { "diamond.falling.delay",                   "4"                     },
-  { "diamond.collecting",                      "RocksCollect.png"      },
-  { "diamond.collecting.xpos",                 "0"                     },
-  { "diamond.collecting.ypos",                 "1"                     },
-  { "diamond.collecting.frames",               "7"                     },
-  { "diamond.collecting.anim_mode",            "linear"                },
-
-  { "bomb",                                    "RocksElements.png"     },
-  { "bomb.xpos",                               "11"                    },
-  { "bomb.ypos",                               "1"                     },
-  { "bomb.frames",                             "1"                     },
-
-  { "nut",                                     "RocksElements.png"     },
-  { "nut.xpos",                                        "12"                    },
-  { "nut.ypos",                                        "1"                     },
-  { "nut.frames",                              "1"                     },
-  { "nut.breaking",                            "RocksElements.png"     },
-  { "nut.breaking.xpos",                       "13"                    },
-  { "nut.breaking.ypos",                       "1"                     },
-  { "nut.breaking.frames",                     "3"                     },
-  { "nut.breaking.delay",                      "2"                     },
-  { "nut.breaking.anim_mode",                  "linear"                },
-
-  { "dynamite",                                        "RocksElements.png"     },
-  { "dynamite.xpos",                           "0"                     },
-  { "dynamite.ypos",                           "3"                     },
-  { "dynamite.frames",                         "1"                     },
-  { "dynamite.active",                         "RocksElements.png"     },
-  { "dynamite.active.xpos",                    "1"                     },
-  { "dynamite.active.ypos",                    "3"                     },
-  { "dynamite.active.frames",                  "7"                     },
-  { "dynamite.active.delay",                   "12"                    },
-  { "dynamite.active.anim_mode",               "linear"                },
-  { "dynamite.collecting",                     "RocksCollect.png"      },
-  { "dynamite.collecting.xpos",                        "0"                     },
-  { "dynamite.collecting.ypos",                        "7"                     },
-  { "dynamite.collecting.frames",              "7"                     },
-  { "dynamite.collecting.anim_mode",           "linear"                },
-
-  { "em_dynamite",                             "RocksEMC.png"          },
-  { "em_dynamite.xpos",                                "0"                     },
-  { "em_dynamite.ypos",                                "15"                    },
-  { "em_dynamite.frames",                      "1"                     },
-  { "em_dynamite.active",                      "RocksEMC.png"          },
-  { "em_dynamite.active.xpos",                 "1"                     },
-  { "em_dynamite.active.ypos",                 "15"                    },
-  { "em_dynamite.active.frames",               "4"                     },
-  { "em_dynamite.active.delay",                        "8"                     },
-  { "em_dynamite.active.anim_mode",            "linear"                },
-  { "em_dynamite.active.EDITOR",               "RocksEMC.png"          },
-  { "em_dynamite.active.EDITOR.xpos",          "2"                     },
-  { "em_dynamite.active.EDITOR.ypos",          "15"                    },
-  { "em_dynamite.collecting",                  "RocksCollect.png"      },
-  { "em_dynamite.collecting.xpos",             "0"                     },
-  { "em_dynamite.collecting.ypos",             "15"                    },
-  { "em_dynamite.collecting.frames",           "7"                     },
-  { "em_dynamite.collecting.anim_mode",                "linear"                },
-
-  { "wall_emerald",                            "RocksElements.png"     },
-  { "wall_emerald.xpos",                       "4"                     },
-  { "wall_emerald.ypos",                       "8"                     },
-  { "wall_emerald.frames",                     "1"                     },
-
-  { "wall_diamond",                            "RocksElements.png"     },
-  { "wall_diamond.xpos",                       "5"                     },
-  { "wall_diamond.ypos",                       "8"                     },
-  { "wall_diamond.frames",                     "1"                     },
-
-  { "bug",                                     "RocksElements.png"     },
-  { "bug.xpos",                                        "8"                     },
-  { "bug.ypos",                                        "4"                     },
-  { "bug.frames",                              "4"                     },
-  { "bug.delay",                               "8"                     },
-  { "bug.right",                               "RocksElements.png"     },
-  { "bug.right.xpos",                          "8"                     },
-  { "bug.right.ypos",                          "4"                     },
-  { "bug.right.frames",                                "1"                     },
-  { "bug.up",                                  "RocksElements.png"     },
-  { "bug.up.xpos",                             "9"                     },
-  { "bug.up.ypos",                             "4"                     },
-  { "bug.up.frames",                           "1"                     },
-  { "bug.left",                                        "RocksElements.png"     },
-  { "bug.left.xpos",                           "10"                    },
-  { "bug.left.ypos",                           "4"                     },
-  { "bug.left.frames",                         "1"                     },
-  { "bug.down",                                        "RocksElements.png"     },
-  { "bug.down.xpos",                           "11"                    },
-  { "bug.down.ypos",                           "4"                     },
-  { "bug.down.frames",                         "1"                     },
-  { "bug.moving.right",                                "RocksElements.png"     },
-  { "bug.moving.right.xpos",                   "8"                     },
-  { "bug.moving.right.ypos",                   "4"                     },
-  { "bug.moving.right.frames",                 "2"                     },
-  { "bug.moving.right.delay",                  "4"                     },
-  { "bug.moving.right.offset",                 "128"                   },
-  { "bug.moving.up",                           "RocksElements.png"     },
-  { "bug.moving.up.xpos",                      "9"                     },
-  { "bug.moving.up.ypos",                      "4"                     },
-  { "bug.moving.up.frames",                    "2"                     },
-  { "bug.moving.up.delay",                     "4"                     },
-  { "bug.moving.up.offset",                    "128"                   },
-  { "bug.moving.left",                         "RocksElements.png"     },
-  { "bug.moving.left.xpos",                    "10"                    },
-  { "bug.moving.left.ypos",                    "4"                     },
-  { "bug.moving.left.frames",                  "2"                     },
-  { "bug.moving.left.delay",                   "4"                     },
-  { "bug.moving.left.offset",                  "128"                   },
-  { "bug.moving.down",                         "RocksElements.png"     },
-  { "bug.moving.down.xpos",                    "11"                    },
-  { "bug.moving.down.ypos",                    "4"                     },
-  { "bug.moving.down.frames",                  "2"                     },
-  { "bug.moving.down.delay",                   "4"                     },
-  { "bug.moving.down.offset",                  "128"                   },
-  { "bug.turning_from_right.up",               "RocksMore.png"         },
-  { "bug.turning_from_right.up.xpos",          "0"                     },
-  { "bug.turning_from_right.up.ypos",          "6"                     },
-  { "bug.turning_from_right.up.frames",                "4"                     },
-  { "bug.turning_from_right.up.delay",         "2"                     },
-  { "bug.turning_from_right.up.anim_mode",     "linear,reverse"        },
-  { "bug.turning_from_up.left",                        "RocksMore.png"         },
-  { "bug.turning_from_up.left.xpos",           "12"                    },
-  { "bug.turning_from_up.left.ypos",           "6"                     },
-  { "bug.turning_from_up.left.frames",         "4"                     },
-  { "bug.turning_from_up.left.delay",          "2"                     },
-  { "bug.turning_from_up.left.anim_mode",      "linear,reverse"        },
-  { "bug.turning_from_left.down",              "RocksMore.png"         },
-  { "bug.turning_from_left.down.xpos",         "8"                     },
-  { "bug.turning_from_left.down.ypos",         "6"                     },
-  { "bug.turning_from_left.down.frames",       "4"                     },
-  { "bug.turning_from_left.down.delay",                "2"                     },
-  { "bug.turning_from_left.down.anim_mode",    "linear,reverse"        },
-  { "bug.turning_from_down.right",             "RocksMore.png"         },
-  { "bug.turning_from_down.right.xpos",                "4"                     },
-  { "bug.turning_from_down.right.ypos",                "6"                     },
-  { "bug.turning_from_down.right.frames",      "4"                     },
-  { "bug.turning_from_down.right.delay",       "2"                     },
-  { "bug.turning_from_down.right.anim_mode",   "linear,reverse"        },
-  { "bug.turning_from_right.down",             "RocksMore.png"         },
-  { "bug.turning_from_right.down.xpos",                "5"                     },
-  { "bug.turning_from_right.down.ypos",                "6"                     },
-  { "bug.turning_from_right.down.frames",      "4"                     },
-  { "bug.turning_from_right.down.delay",       "2"                     },
-  { "bug.turning_from_right.down.anim_mode",   "linear"                },
-  { "bug.turning_from_up.right",               "RocksMore.png"         },
-  { "bug.turning_from_up.right.xpos",          "1"                     },
-  { "bug.turning_from_up.right.ypos",          "6"                     },
-  { "bug.turning_from_up.right.frames",                "4"                     },
-  { "bug.turning_from_up.right.delay",         "2"                     },
-  { "bug.turning_from_up.right.anim_mode",     "linear"                },
-  { "bug.turning_from_left.up",                        "RocksMore.png"         },
-  { "bug.turning_from_left.up.xpos",           "13"                    },
-  { "bug.turning_from_left.up.ypos",           "6"                     },
-  { "bug.turning_from_left.up.frames",         "4"                     },
-  { "bug.turning_from_left.up.delay",          "2"                     },
-  { "bug.turning_from_left.up.anim_mode",      "linear"                },
-  { "bug.turning_from_down.left",              "RocksMore.png"         },
-  { "bug.turning_from_down.left.xpos",         "9"                     },
-  { "bug.turning_from_down.left.ypos",         "6"                     },
-  { "bug.turning_from_down.left.frames",       "4"                     },
-  { "bug.turning_from_down.left.delay",                "2"                     },
-  { "bug.turning_from_down.left.anim_mode",    "linear"                },
-
-  { "spaceship",                               "RocksElements.png"     },
-  { "spaceship.xpos",                          "8"                     },
-  { "spaceship.ypos",                          "3"                     },
-  { "spaceship.frames",                                "4"                     },
-  { "spaceship.delay",                         "8"                     },
-  { "spaceship.right",                         "RocksElements.png"     },
-  { "spaceship.right.xpos",                    "8"                     },
-  { "spaceship.right.ypos",                    "3"                     },
-  { "spaceship.right.frames",                  "1"                     },
-  { "spaceship.up",                            "RocksElements.png"     },
-  { "spaceship.up.xpos",                       "9"                     },
-  { "spaceship.up.ypos",                       "3"                     },
-  { "spaceship.up.frames",                     "1"                     },
-  { "spaceship.left",                          "RocksElements.png"     },
-  { "spaceship.left.xpos",                     "10"                    },
-  { "spaceship.left.ypos",                     "3"                     },
-  { "spaceship.left.frames",                   "1"                     },
-  { "spaceship.down",                          "RocksElements.png"     },
-  { "spaceship.down.xpos",                     "11"                    },
-  { "spaceship.down.ypos",                     "3"                     },
-  { "spaceship.down.frames",                   "1"                     },
-  { "spaceship.moving.right",                  "RocksElements.png"     },
-  { "spaceship.moving.right.xpos",             "8"                     },
-  { "spaceship.moving.right.ypos",             "3"                     },
-  { "spaceship.moving.right.frames",           "2"                     },
-  { "spaceship.moving.right.delay",            "4"                     },
-  { "spaceship.moving.right.offset",           "128"                   },
-  { "spaceship.moving.up",                     "RocksElements.png"     },
-  { "spaceship.moving.up.xpos",                        "9"                     },
-  { "spaceship.moving.up.ypos",                        "3"                     },
-  { "spaceship.moving.up.frames",              "2"                     },
-  { "spaceship.moving.up.delay",               "4"                     },
-  { "spaceship.moving.up.offset",              "128"                   },
-  { "spaceship.moving.left",                   "RocksElements.png"     },
-  { "spaceship.moving.left.xpos",              "10"                    },
-  { "spaceship.moving.left.ypos",              "3"                     },
-  { "spaceship.moving.left.frames",            "2"                     },
-  { "spaceship.moving.left.delay",             "4"                     },
-  { "spaceship.moving.left.offset",            "128"                   },
-  { "spaceship.moving.down",                   "RocksElements.png"     },
-  { "spaceship.moving.down.xpos",              "11"                    },
-  { "spaceship.moving.down.ypos",              "3"                     },
-  { "spaceship.moving.down.frames",            "2"                     },
-  { "spaceship.moving.down.delay",             "4"                     },
-  { "spaceship.moving.down.offset",            "128"                   },
-  { "spaceship.turning_from_right.up",         "RocksMore.png"         },
-  { "spaceship.turning_from_right.up.xpos",    "0"                     },
-  { "spaceship.turning_from_right.up.ypos",    "5"                     },
-  { "spaceship.turning_from_right.up.frames",  "4"                     },
-  { "spaceship.turning_from_right.up.delay",   "2"                     },
-  { "spaceship.turning_from_right.up.anim_mode","linear,reverse"       },
-  { "spaceship.turning_from_up.left",          "RocksMore.png"         },
-  { "spaceship.turning_from_up.left.xpos",     "12"                    },
-  { "spaceship.turning_from_up.left.ypos",     "5"                     },
-  { "spaceship.turning_from_up.left.frames",   "4"                     },
-  { "spaceship.turning_from_up.left.delay",    "2"                     },
-  { "spaceship.turning_from_up.left.anim_mode",        "linear,reverse"        },
-  { "spaceship.turning_from_left.down",                "RocksMore.png"         },
-  { "spaceship.turning_from_left.down.xpos",   "8"                     },
-  { "spaceship.turning_from_left.down.ypos",   "5"                     },
-  { "spaceship.turning_from_left.down.frames", "4"                     },
-  { "spaceship.turning_from_left.down.delay",  "2"                     },
-  { "spaceship.turning_from_left.down.anim_mode","linear,reverse"      },
-  { "spaceship.turning_from_down.right",       "RocksMore.png"         },
-  { "spaceship.turning_from_down.right.xpos",  "4"                     },
-  { "spaceship.turning_from_down.right.ypos",  "5"                     },
-  { "spaceship.turning_from_down.right.frames",        "4"                     },
-  { "spaceship.turning_from_down.right.delay", "2"                     },
-  { "spaceship.turning_from_down.right.anim_mode","linear,reverse"     },
-  { "spaceship.turning_from_right.down",       "RocksMore.png"         },
-  { "spaceship.turning_from_right.down.xpos",  "5"                     },
-  { "spaceship.turning_from_right.down.ypos",  "5"                     },
-  { "spaceship.turning_from_right.down.frames",        "4"                     },
-  { "spaceship.turning_from_right.down.delay", "2"                     },
-  { "spaceship.turning_from_right.down.anim_mode","linear"             },
-  { "spaceship.turning_from_up.right",         "RocksMore.png"         },
-  { "spaceship.turning_from_up.right.xpos",    "1"                     },
-  { "spaceship.turning_from_up.right.ypos",    "5"                     },
-  { "spaceship.turning_from_up.right.frames",  "4"                     },
-  { "spaceship.turning_from_up.right.delay",   "2"                     },
-  { "spaceship.turning_from_up.right.anim_mode","linear"               },
-  { "spaceship.turning_from_left.up",          "RocksMore.png"         },
-  { "spaceship.turning_from_left.up.xpos",     "13"                    },
-  { "spaceship.turning_from_left.up.ypos",     "5"                     },
-  { "spaceship.turning_from_left.up.frames",   "4"                     },
-  { "spaceship.turning_from_left.up.delay",    "2"                     },
-  { "spaceship.turning_from_left.up.anim_mode",        "linear"                },
-  { "spaceship.turning_from_down.left",                "RocksMore.png"         },
-  { "spaceship.turning_from_down.left.xpos",   "9"                     },
-  { "spaceship.turning_from_down.left.ypos",   "5"                     },
-  { "spaceship.turning_from_down.left.frames", "4"                     },
-  { "spaceship.turning_from_down.left.delay",  "2"                     },
-  { "spaceship.turning_from_down.left.anim_mode","linear"              },
-
-  { "yamyam",                                  "RocksElements.png"     },
-  { "yamyam.xpos",                             "0"                     },
-  { "yamyam.ypos",                             "5"                     },
-  { "yamyam.frames",                           "4"                     },
-  { "yamyam.anim_mode",                                "pingpong2"             },
-  { "yamyam.left",                             "RocksElements.png"     },
-  { "yamyam.left.xpos",                                "0"                     },
-  { "yamyam.left.ypos",                                "5"                     },
-  { "yamyam.left.frames",                      "4"                     },
-  { "yamyam.left.anim_mode",                   "pingpong2"             },
-  { "yamyam.left.EDITOR",                      "RocksEMC.png"          },
-  { "yamyam.left.EDITOR.xpos",                 "7"                     },
-  { "yamyam.left.EDITOR.ypos",                 "15"                    },
-  { "yamyam.right",                            "RocksElements.png"     },
-  { "yamyam.right.xpos",                       "0"                     },
-  { "yamyam.right.ypos",                       "5"                     },
-  { "yamyam.right.frames",                     "4"                     },
-  { "yamyam.right.anim_mode",                  "pingpong2"             },
-  { "yamyam.right.EDITOR",                     "RocksEMC.png"          },
-  { "yamyam.right.EDITOR.xpos",                        "8"                     },
-  { "yamyam.right.EDITOR.ypos",                        "15"                    },
-  { "yamyam.up",                               "RocksElements.png"     },
-  { "yamyam.up.xpos",                          "0"                     },
-  { "yamyam.up.ypos",                          "5"                     },
-  { "yamyam.up.frames",                                "4"                     },
-  { "yamyam.up.anim_mode",                     "pingpong2"             },
-  { "yamyam.up.EDITOR",                                "RocksEMC.png"          },
-  { "yamyam.up.EDITOR.xpos",                   "5"                     },
-  { "yamyam.up.EDITOR.ypos",                   "15"                    },
-  { "yamyam.down",                             "RocksElements.png"     },
-  { "yamyam.down.xpos",                                "0"                     },
-  { "yamyam.down.ypos",                                "5"                     },
-  { "yamyam.down.frames",                      "4"                     },
-  { "yamyam.down.anim_mode",                   "pingpong2"             },
-  { "yamyam.down.EDITOR",                      "RocksEMC.png"          },
-  { "yamyam.down.EDITOR.xpos",                 "6"                     },
-  { "yamyam.down.EDITOR.ypos",                 "15"                    },
-  { "yamyam.moving",                           "RocksElements.png"     },
-  { "yamyam.moving.xpos",                      "0"                     },
-  { "yamyam.moving.ypos",                      "5"                     },
-  { "yamyam.moving.frames",                    "1"                     },
-
-  { "robot",                                   "RocksElements.png"     },
-  { "robot.xpos",                              "4"                     },
-  { "robot.ypos",                              "5"                     },
-  { "robot.frames",                            "4"                     },
-  { "robot.anim_mode",                         "pingpong2"             },
-  { "robot.moving",                            "RocksElements.png"     },
-  { "robot.moving.xpos",                       "4"                     },
-  { "robot.moving.ypos",                       "5"                     },
-  { "robot.moving.frames",                     "1"                     },
-
-  { "robot_wheel",                             "RocksElements.png"     },
-  { "robot_wheel.xpos",                                "0"                     },
-  { "robot_wheel.ypos",                                "6"                     },
-  { "robot_wheel.frames",                      "1"                     },
-  { "robot_wheel.active",                      "RocksElements.png"     },
-  { "robot_wheel.active.xpos",                 "0"                     },
-  { "robot_wheel.active.ypos",                 "6"                     },
-  { "robot_wheel.active.frames",               "4"                     },
-
-  { "magic_wall",                              "RocksElements.png"     },
-  { "magic_wall.xpos",                         "0"                     },
-  { "magic_wall.ypos",                         "8"                     },
-  { "magic_wall.frames",                       "1"                     },
-  { "magic_wall.active",                       "RocksElements.png"     },
-  { "magic_wall.active.xpos",                  "0"                     },
-  { "magic_wall.active.ypos",                  "8"                     },
-  { "magic_wall.active.frames",                        "4"                     },
-  { "magic_wall.active.anim_mode",             "reverse"               },
-  { "magic_wall.active.delay",                 "4"                     },
-  { "magic_wall.active.global_sync",           "true"                  },
-  { "magic_wall.filling",                      "RocksElements.png"     },
-  { "magic_wall.filling.xpos",                 "0"                     },
-  { "magic_wall.filling.ypos",                 "8"                     },
-  { "magic_wall.filling.frames",               "4"                     },
-  { "magic_wall.filling.anim_mode",            "reverse"               },
-  { "magic_wall.filling.delay",                        "4"                     },
-  { "magic_wall.filling.global_sync",          "true"                  },
-  { "magic_wall_full",                         "RocksElements.png"     },
-  { "magic_wall_full.xpos",                    "0"                     },
-  { "magic_wall_full.ypos",                    "8"                     },
-  { "magic_wall_full.frames",                  "4"                     },
-  { "magic_wall_full.anim_mode",               "reverse"               },
-  { "magic_wall_full.delay",                   "4"                     },
-  { "magic_wall_full.global_sync",             "true"                  },
-  { "magic_wall.emptying",                     "RocksElements.png"     },
-  { "magic_wall.emptying.xpos",                        "0"                     },
-  { "magic_wall.emptying.ypos",                        "8"                     },
-  { "magic_wall.emptying.frames",              "4"                     },
-  { "magic_wall.emptying.anim_mode",           "reverse"               },
-  { "magic_wall.emptying.delay",               "4"                     },
-  { "magic_wall.emptying.global_sync",         "true"                  },
-  { "magic_wall_dead",                         "RocksElements.png"     },
-  { "magic_wall_dead.xpos",                    "0"                     },
-  { "magic_wall_dead.ypos",                    "8"                     },
-  { "magic_wall_dead.frames",                  "1"                     },
-
-  { "dc_magic_wall",                           "RocksDC2.png"          },
-  { "dc_magic_wall.xpos",                      "0"                     },
-  { "dc_magic_wall.ypos",                      "3"                     },
-  { "dc_magic_wall.frames",                    "1"                     },
-  { "dc_magic_wall.active",                    "RocksDC2.png"          },
-  { "dc_magic_wall.active.xpos",               "0"                     },
-  { "dc_magic_wall.active.ypos",               "3"                     },
-  { "dc_magic_wall.active.frames",             "4"                     },
-  { "dc_magic_wall.active.anim_mode",          "reverse"               },
-  { "dc_magic_wall.active.delay",              "4"                     },
-  { "dc_magic_wall.active.global_sync",                "true"                  },
-  { "dc_magic_wall.filling",                   "RocksDC2.png"          },
-  { "dc_magic_wall.filling.xpos",              "0"                     },
-  { "dc_magic_wall.filling.ypos",              "3"                     },
-  { "dc_magic_wall.filling.frames",            "4"                     },
-  { "dc_magic_wall.filling.anim_mode",         "reverse"               },
-  { "dc_magic_wall.filling.delay",             "4"                     },
-  { "dc_magic_wall.filling.global_sync",       "true"                  },
-  { "dc_magic_wall_full",                      "RocksDC2.png"          },
-  { "dc_magic_wall_full.xpos",                 "0"                     },
-  { "dc_magic_wall_full.ypos",                 "3"                     },
-  { "dc_magic_wall_full.frames",               "4"                     },
-  { "dc_magic_wall_full.anim_mode",            "reverse"               },
-  { "dc_magic_wall_full.delay",                        "4"                     },
-  { "dc_magic_wall_full.global_sync",          "true"                  },
-  { "dc_magic_wall.emptying",                  "RocksDC2.png"          },
-  { "dc_magic_wall.emptying.xpos",             "0"                     },
-  { "dc_magic_wall.emptying.ypos",             "3"                     },
-  { "dc_magic_wall.emptying.frames",           "4"                     },
-  { "dc_magic_wall.emptying.anim_mode",                "reverse"               },
-  { "dc_magic_wall.emptying.delay",            "4"                     },
-  { "dc_magic_wall.emptying.global_sync",      "true"                  },
-  { "dc_magic_wall_dead",                      "RocksDC2.png"          },
-  { "dc_magic_wall_dead.xpos",                 "0"                     },
-  { "dc_magic_wall_dead.ypos",                 "3"                     },
-  { "dc_magic_wall_dead.frames",               "1"                     },
-
-  { "quicksand_empty",                         "RocksElements.png"     },
-  { "quicksand_empty.xpos",                    "2"                     },
-  { "quicksand_empty.ypos",                    "0"                     },
-  { "quicksand_empty.frames",                  "1"                     },
-  { "quicksand.filling",                       "RocksElements.png"     },
-  { "quicksand.filling.xpos",                  "3"                     },
-  { "quicksand.filling.ypos",                  "0"                     },
-  { "quicksand.filling.frames",                        "1"                     },
-  { "quicksand_full",                          "RocksElements.png"     },
-  { "quicksand_full.xpos",                     "3"                     },
-  { "quicksand_full.ypos",                     "0"                     },
-  { "quicksand_full.frames",                   "1"                     },
-  { "quicksand_full.EDITOR",                   "RocksElements.png"     },
-  { "quicksand_full.EDITOR.xpos",              "3"                     },
-  { "quicksand_full.EDITOR.ypos",              "14"                    },
-  { "quicksand.emptying",                      "RocksElements.png"     },
-  { "quicksand.emptying.xpos",                 "3"                     },
-  { "quicksand.emptying.ypos",                 "0"                     },
-  { "quicksand.emptying.frames",               "1"                     },
-
-  { "quicksand_fast_empty",                    "RocksDC2.png"          },
-  { "quicksand_fast_empty.xpos",               "4"                     },
-  { "quicksand_fast_empty.ypos",               "3"                     },
-  { "quicksand_fast_empty.frames",             "1"                     },
-  { "quicksand_fast.filling",                  "RocksDC2.png"          },
-  { "quicksand_fast.filling.xpos",             "4"                     },
-  { "quicksand_fast.filling.ypos",             "3"                     },
-  { "quicksand_fast.filling.frames",           "1"                     },
-  { "quicksand_fast_full",                     "RocksDC2.png"          },
-  { "quicksand_fast_full.xpos",                        "4"                     },
-  { "quicksand_fast_full.ypos",                        "3"                     },
-  { "quicksand_fast_full.frames",              "1"                     },
-  { "quicksand_fast_full.EDITOR",              "RocksDC2.png"          },
-  { "quicksand_fast_full.EDITOR.xpos",         "5"                     },
-  { "quicksand_fast_full.EDITOR.ypos",         "3"                     },
-  { "quicksand_fast.emptying",                 "RocksDC2.png"          },
-  { "quicksand_fast.emptying.xpos",            "4"                     },
-  { "quicksand_fast.emptying.ypos",            "3"                     },
-  { "quicksand_fast.emptying.frames",          "1"                     },
-
-  { "acid_pool_topleft",                       "RocksElements.png"     },
-  { "acid_pool_topleft.xpos",                  "0"                     },
-  { "acid_pool_topleft.ypos",                  "1"                     },
-  { "acid_pool_topleft.frames",                        "1"                     },
-  { "acid_pool_topright",                      "RocksElements.png"     },
-  { "acid_pool_topright.xpos",                 "2"                     },
-  { "acid_pool_topright.ypos",                 "1"                     },
-  { "acid_pool_topright.frames",               "1"                     },
-  { "acid_pool_bottomleft",                    "RocksElements.png"     },
-  { "acid_pool_bottomleft.xpos",               "0"                     },
-  { "acid_pool_bottomleft.ypos",               "2"                     },
-  { "acid_pool_bottomleft.frames",             "1"                     },
-  { "acid_pool_bottom",                                "RocksElements.png"     },
-  { "acid_pool_bottom.xpos",                   "1"                     },
-  { "acid_pool_bottom.ypos",                   "2"                     },
-  { "acid_pool_bottom.frames",                 "1"                     },
-  { "acid_pool_bottomright",                   "RocksElements.png"     },
-  { "acid_pool_bottomright.xpos",              "2"                     },
-  { "acid_pool_bottomright.ypos",              "2"                     },
-  { "acid_pool_bottomright.frames",            "1"                     },
-
-  { "acid",                                    "RocksElements.png"     },
-  { "acid.xpos",                               "12"                    },
-  { "acid.ypos",                               "7"                     },
-  { "acid.frames",                             "4"                     },
-  { "acid.delay",                              "10"                    },
-  { "acid.global_sync",                                "true"                  },
-
-  { "acid_splash_left",                                "RocksHeroes.png"       },
-  { "acid_splash_left.xpos",                   "8"                     },
-  { "acid_splash_left.ypos",                   "10"                    },
-  { "acid_splash_left.frames",                 "4"                     },
-  { "acid_splash_left.delay",                  "2"                     },
-  { "acid_splash_left.anim_mode",              "linear"                },
-  { "acid_splash_right",                       "RocksHeroes.png"       },
-  { "acid_splash_right.xpos",                  "12"                    },
-  { "acid_splash_right.ypos",                  "10"                    },
-  { "acid_splash_right.frames",                        "4"                     },
-  { "acid_splash_right.delay",                 "2"                     },
-  { "acid_splash_right.anim_mode",             "linear"                },
-
-  { "amoeba_drop",                             "RocksElements.png"     },
-  { "amoeba_drop.xpos",                                "5"                     },
-  { "amoeba_drop.ypos",                                "6"                     },
-  { "amoeba_drop.frames",                      "1"                     },
-  { "amoeba.growing",                          "RocksElements.png"     },
-  { "amoeba.growing.xpos",                     "5"                     },
-  { "amoeba.growing.ypos",                     "6"                     },
-  { "amoeba.growing.frames",                   "3"                     },
-  { "amoeba.growing.delay",                    "2"                     },
-  { "amoeba.growing.anim_mode",                        "linear"                },
-  { "amoeba.shrinking",                                "RocksElements.png"     },
-  { "amoeba.shrinking.xpos",                   "5"                     },
-  { "amoeba.shrinking.ypos",                   "6"                     },
-  { "amoeba.shrinking.frames",                 "3"                     },
-  { "amoeba.shrinking.delay",                  "2"                     },
-  { "amoeba.shrinking.anim_mode",              "linear,reverse"        },
-  { "amoeba_wet",                              "RocksElements.png"     },
-  { "amoeba_wet.xpos",                         "8"                     },
-  { "amoeba_wet.ypos",                         "6"                     },
-  { "amoeba_wet.frames",                       "4"                     },
-  { "amoeba_wet.delay",                                "1000000"               },
-  { "amoeba_wet.anim_mode",                    "random"                },
-  { "amoeba_wet.EDITOR",                       "RocksElements.png"     },
-  { "amoeba_wet.EDITOR.xpos",                  "4"                     },
-  { "amoeba_wet.EDITOR.ypos",                  "6"                     },
-  { "amoeba.dropping",                         "RocksElements.png"     },
-  { "amoeba.dropping.xpos",                    "8"                     },
-  { "amoeba.dropping.ypos",                    "6"                     },
-  { "amoeba.dropping.frames",                  "4"                     },
-  { "amoeba.dropping.delay",                   "1000000"               },
-  { "amoeba.dropping.anim_mode",               "random"                },
-  { "amoeba_dry",                              "RocksElements.png"     },
-  { "amoeba_dry.xpos",                         "8"                     },
-  { "amoeba_dry.ypos",                         "6"                     },
-  { "amoeba_dry.frames",                       "4"                     },
-  { "amoeba_dry.delay",                                "1000000"               },
-  { "amoeba_dry.anim_mode",                    "random"                },
-  { "amoeba_full",                             "RocksElements.png"     },
-  { "amoeba_full.xpos",                                "8"                     },
-  { "amoeba_full.ypos",                                "6"                     },
-  { "amoeba_full.frames",                      "4"                     },
-  { "amoeba_full.delay",                       "1000000"               },
-  { "amoeba_full.anim_mode",                   "random"                },
-  { "amoeba_full.EDITOR",                      "RocksElements.png"     },
-  { "amoeba_full.EDITOR.xpos",                 "8"                     },
-  { "amoeba_full.EDITOR.ypos",                 "7"                     },
-  { "amoeba_dead",                             "RocksElements.png"     },
-  { "amoeba_dead.xpos",                                "12"                    },
-  { "amoeba_dead.ypos",                                "6"                     },
-  { "amoeba_dead.frames",                      "4"                     },
-  { "amoeba_dead.delay",                       "1000000"               },
-  { "amoeba_dead.anim_mode",                   "random"                },
-  { "amoeba_dead.EDITOR",                      "RocksElements.png"     },
-  { "amoeba_dead.EDITOR.xpos",                 "12"                    },
-  { "amoeba_dead.EDITOR.ypos",                 "6"                     },
-
-  { "em_key_1",                                        "RocksSP.png"           },
-  { "em_key_1.xpos",                           "4"                     },
-  { "em_key_1.ypos",                           "6"                     },
-  { "em_key_1.frames",                         "1"                     },
-  { "em_key_1.collecting",                     "RocksCollect.png"      },
-  { "em_key_1.collecting.xpos",                        "7"                     },
-  { "em_key_1.collecting.ypos",                        "4"                     },
-  { "em_key_1.collecting.frames",              "7"                     },
-  { "em_key_1.collecting.anim_mode",           "linear"                },
-  { "em_key_2",                                        "RocksSP.png"           },
-  { "em_key_2.xpos",                           "5"                     },
-  { "em_key_2.ypos",                           "6"                     },
-  { "em_key_2.frames",                         "1"                     },
-  { "em_key_2.collecting",                     "RocksCollect.png"      },
-  { "em_key_2.collecting.xpos",                        "7"                     },
-  { "em_key_2.collecting.ypos",                        "5"                     },
-  { "em_key_2.collecting.frames",              "7"                     },
-  { "em_key_2.collecting.anim_mode",           "linear"                },
-  { "em_key_3",                                        "RocksSP.png"           },
-  { "em_key_3.xpos",                           "6"                     },
-  { "em_key_3.ypos",                           "6"                     },
-  { "em_key_3.frames",                         "1"                     },
-  { "em_key_3.collecting",                     "RocksCollect.png"      },
-  { "em_key_3.collecting.xpos",                        "7"                     },
-  { "em_key_3.collecting.ypos",                        "6"                     },
-  { "em_key_3.collecting.frames",              "7"                     },
-  { "em_key_3.collecting.anim_mode",           "linear"                },
-  { "em_key_4",                                        "RocksSP.png"           },
-  { "em_key_4.xpos",                           "7"                     },
-  { "em_key_4.ypos",                           "6"                     },
-  { "em_key_4.frames",                         "1"                     },
-  { "em_key_4.collecting",                     "RocksCollect.png"      },
-  { "em_key_4.collecting.xpos",                        "7"                     },
-  { "em_key_4.collecting.ypos",                        "7"                     },
-  { "em_key_4.collecting.frames",              "7"                     },
-  { "em_key_4.collecting.anim_mode",           "linear"                },
-
-  { "dc_key_white",                            "RocksSP.png"           },
-  { "dc_key_white.xpos",                       "13"                    },
-  { "dc_key_white.ypos",                       "1"                     },
-  { "dc_key_white.frames",                     "1"                     },
-  { "dc_key_white.collecting",                 "RocksCollect.png"      },
-  { "dc_key_white.collecting.xpos",            "7"                     },
-  { "dc_key_white.collecting.ypos",            "0"                     },
-  { "dc_key_white.collecting.frames",          "7"                     },
-  { "dc_key_white.collecting.anim_mode",       "linear"                },
-
-  { "em_gate_1",                               "RocksSP.png"           },
-  { "em_gate_1.xpos",                          "0"                     },
-  { "em_gate_1.ypos",                          "7"                     },
-  { "em_gate_1.frames",                                "1"                     },
-  { "em_gate_2",                               "RocksSP.png"           },
-  { "em_gate_2.xpos",                          "1"                     },
-  { "em_gate_2.ypos",                          "7"                     },
-  { "em_gate_2.frames",                                "1"                     },
-  { "em_gate_3",                               "RocksSP.png"           },
-  { "em_gate_3.xpos",                          "2"                     },
-  { "em_gate_3.ypos",                          "7"                     },
-  { "em_gate_3.frames",                                "1"                     },
-  { "em_gate_4",                               "RocksSP.png"           },
-  { "em_gate_4.xpos",                          "3"                     },
-  { "em_gate_4.ypos",                          "7"                     },
-  { "em_gate_4.frames",                                "1"                     },
-
-  { "dc_gate_white",                           "RocksSP.png"           },
-  { "dc_gate_white.xpos",                      "14"                    },
-  { "dc_gate_white.ypos",                      "1"                     },
-  { "dc_gate_white.frames",                    "1"                     },
-
-  { "em_gate_1_gray",                          "RocksSP.png"           },
-  { "em_gate_1_gray.xpos",                     "4"                     },
-  { "em_gate_1_gray.ypos",                     "7"                     },
-  { "em_gate_1_gray.frames",                   "1"                     },
-  { "em_gate_1_gray.EDITOR",                   "RocksSP.png"           },
-  { "em_gate_1_gray.EDITOR.xpos",              "12"                    },
-  { "em_gate_1_gray.EDITOR.ypos",              "11"                    },
-  { "em_gate_1_gray.active",                   "RocksSP.png"           },
-  { "em_gate_1_gray.active.xpos",              "0"                     },
-  { "em_gate_1_gray.active.ypos",              "7"                     },
-  { "em_gate_1_gray.active.frames",            "1"                     },
-  { "em_gate_2_gray",                          "RocksSP.png"           },
-  { "em_gate_2_gray.xpos",                     "5"                     },
-  { "em_gate_2_gray.ypos",                     "7"                     },
-  { "em_gate_2_gray.frames",                   "1"                     },
-  { "em_gate_2_gray.EDITOR",                   "RocksSP.png"           },
-  { "em_gate_2_gray.EDITOR.xpos",              "13"                    },
-  { "em_gate_2_gray.EDITOR.ypos",              "11"                    },
-  { "em_gate_2_gray.active",                   "RocksSP.png"           },
-  { "em_gate_2_gray.active.xpos",              "1"                     },
-  { "em_gate_2_gray.active.ypos",              "7"                     },
-  { "em_gate_2_gray.active.frames",            "1"                     },
-  { "em_gate_3_gray",                          "RocksSP.png"           },
-  { "em_gate_3_gray.xpos",                     "6"                     },
-  { "em_gate_3_gray.ypos",                     "7"                     },
-  { "em_gate_3_gray.frames",                   "1"                     },
-  { "em_gate_3_gray.EDITOR",                   "RocksSP.png"           },
-  { "em_gate_3_gray.EDITOR.xpos",              "14"                    },
-  { "em_gate_3_gray.EDITOR.ypos",              "11"                    },
-  { "em_gate_3_gray.active",                   "RocksSP.png"           },
-  { "em_gate_3_gray.active.xpos",              "2"                     },
-  { "em_gate_3_gray.active.ypos",              "7"                     },
-  { "em_gate_3_gray.active.frames",            "1"                     },
-  { "em_gate_4_gray",                          "RocksSP.png"           },
-  { "em_gate_4_gray.xpos",                     "7"                     },
-  { "em_gate_4_gray.ypos",                     "7"                     },
-  { "em_gate_4_gray.frames",                   "1"                     },
-  { "em_gate_4_gray.EDITOR",                   "RocksSP.png"           },
-  { "em_gate_4_gray.EDITOR.xpos",              "15"                    },
-  { "em_gate_4_gray.EDITOR.ypos",              "11"                    },
-  { "em_gate_4_gray.active",                   "RocksSP.png"           },
-  { "em_gate_4_gray.active.xpos",              "3"                     },
-  { "em_gate_4_gray.active.ypos",              "7"                     },
-  { "em_gate_4_gray.active.frames",            "1"                     },
-
-  { "dc_gate_white_gray",                      "RocksSP.png"           },
-  { "dc_gate_white_gray.xpos",                 "7"                     },
-  { "dc_gate_white_gray.ypos",                 "7"                     },
-  { "dc_gate_white_gray.frames",               "1"                     },
-  { "dc_gate_white_gray.EDITOR",               "RocksSP.png"           },
-  { "dc_gate_white_gray.EDITOR.xpos",          "15"                    },
-  { "dc_gate_white_gray.EDITOR.ypos",          "1"                     },
-  { "dc_gate_white_gray.active",               "RocksSP.png"           },
-  { "dc_gate_white_gray.active.xpos",          "14"                    },
-  { "dc_gate_white_gray.active.ypos",          "1"                     },
-  { "dc_gate_white_gray.active.frames",                "1"                     },
-
-  { "dc_gate_fake_gray",                       "RocksSP.png"           },
-  { "dc_gate_fake_gray.xpos",                  "7"                     },
-  { "dc_gate_fake_gray.ypos",                  "7"                     },
-  { "dc_gate_fake_gray.frames",                        "1"                     },
-
-  { "exit_closed",                             "RocksElements.png"     },
-  { "exit_closed.xpos",                                "0"                     },
-  { "exit_closed.ypos",                                "11"                    },
-  { "exit_closed.frames",                      "1"                     },
-  { "exit.opening",                            "RocksElements.png"     },
-  { "exit.opening.xpos",                       "0"                     },
-  { "exit.opening.ypos",                       "11"                    },
-  { "exit.opening.frames",                     "5"                     },
-  { "exit.opening.delay",                      "6"                     },
-  { "exit.opening.anim_mode",                  "linear"                },
-  { "exit_open",                               "RocksElements.png"     },
-  { "exit_open.xpos",                          "4"                     },
-  { "exit_open.ypos",                          "11"                    },
-  { "exit_open.frames",                                "4"                     },
-  { "exit_open.delay",                         "4"                     },
-  { "exit_open.anim_mode",                     "pingpong"              },
-  { "exit.closing",                            "RocksElements.png"     },
-  { "exit.closing.xpos",                       "0"                     },
-  { "exit.closing.ypos",                       "11"                    },
-  { "exit.closing.frames",                     "5"                     },
-  { "exit.closing.delay",                      "6"                     },
-  { "exit.closing.anim_mode",                  "linear,reverse"        },
-
-  { "steel_exit_closed",                       "RocksDC2.png"  },
-  { "steel_exit_closed.xpos",                  "8"                     },
-  { "steel_exit_closed.ypos",                  "0"                     },
-  { "steel_exit_closed.frames",                        "1"                     },
-  { "steel_exit.opening",                      "RocksDC2.png"  },
-  { "steel_exit.opening.xpos",                 "8"                     },
-  { "steel_exit.opening.ypos",                 "0"                     },
-  { "steel_exit.opening.frames",               "5"                     },
-  { "steel_exit.opening.delay",                        "6"                     },
-  { "steel_exit.opening.anim_mode",            "linear"                },
-  { "steel_exit_open",                         "RocksDC2.png"  },
-  { "steel_exit_open.xpos",                    "12"                    },
-  { "steel_exit_open.ypos",                    "0"                     },
-  { "steel_exit_open.frames",                  "4"                     },
-  { "steel_exit_open.delay",                   "4"                     },
-  { "steel_exit_open.anim_mode",               "pingpong"              },
-  { "steel_exit.closing",                      "RocksDC2.png"  },
-  { "steel_exit.closing.xpos",                 "8"                     },
-  { "steel_exit.closing.ypos",                 "0"                     },
-  { "steel_exit.closing.frames",               "5"                     },
-  { "steel_exit.closing.delay",                        "6"                     },
-  { "steel_exit.closing.anim_mode",            "linear,reverse"        },
-
-  { "em_exit_closed",                          "RocksDC2.png"  },
-  { "em_exit_closed.xpos",                     "0"                     },
-  { "em_exit_closed.ypos",                     "4"                     },
-  { "em_exit_closed.frames",                   "1"                     },
-  { "em_exit.opening",                         "RocksDC2.png"  },
-  { "em_exit.opening.xpos",                    "0"                     },
-  { "em_exit.opening.ypos",                    "4"                     },
-  { "em_exit.opening.frames",                  "5"                     },
-  { "em_exit.opening.delay",                   "6"                     },
-  { "em_exit.opening.anim_mode",               "linear"                },
-  { "em_exit_open",                            "RocksDC2.png"  },
-  { "em_exit_open.xpos",                       "4"                     },
-  { "em_exit_open.ypos",                       "4"                     },
-  { "em_exit_open.frames",                     "4"                     },
-  { "em_exit_open.delay",                      "4"                     },
-  { "em_exit_open.anim_mode",                  "pingpong"              },
-  { "em_exit.closing",                         "RocksDC2.png"  },
-  { "em_exit.closing.xpos",                    "0"                     },
-  { "em_exit.closing.ypos",                    "6"                     },
-  { "em_exit.closing.frames",                  "5"                     },
-  { "em_exit.closing.delay",                   "6"                     },
-  { "em_exit.closing.anim_mode",               "linear"                },
-
-  { "em_steel_exit_closed",                    "RocksDC2.png"  },
-  { "em_steel_exit_closed.xpos",               "0"                     },
-  { "em_steel_exit_closed.ypos",               "5"                     },
-  { "em_steel_exit_closed.frames",             "1"                     },
-  { "em_steel_exit.opening",                   "RocksDC2.png"  },
-  { "em_steel_exit.opening.xpos",              "0"                     },
-  { "em_steel_exit.opening.ypos",              "5"                     },
-  { "em_steel_exit.opening.frames",            "5"                     },
-  { "em_steel_exit.opening.delay",             "6"                     },
-  { "em_steel_exit.opening.anim_mode",         "linear"                },
-  { "em_steel_exit_open",                      "RocksDC2.png"  },
-  { "em_steel_exit_open.xpos",                 "4"                     },
-  { "em_steel_exit_open.ypos",                 "5"                     },
-  { "em_steel_exit_open.frames",               "4"                     },
-  { "em_steel_exit_open.delay",                        "4"                     },
-  { "em_steel_exit_open.anim_mode",            "pingpong"              },
-  { "em_steel_exit.closing",                   "RocksDC2.png"  },
-  { "em_steel_exit.closing.xpos",              "0"                     },
-  { "em_steel_exit.closing.ypos",              "7"                     },
-  { "em_steel_exit.closing.frames",            "5"                     },
-  { "em_steel_exit.closing.delay",             "6"                     },
-  { "em_steel_exit.closing.anim_mode",         "linear"                },
+  { "empty_space",                                     "RocksSP.png"                   },
+  { "empty_space.xpos",                                        "0"                             },
+  { "empty_space.ypos",                                        "0"                             },
+  { "empty_space.frames",                              "1"                             },
+
+  { "sand",                                            "RocksElements.png"             },
+  { "sand.xpos",                                       "0"                             },
+  { "sand.ypos",                                       "0"                             },
+  { "sand.frames",                                     "1"                             },
+  { "sand.CRUMBLED",                                   "RocksElements.png"             },
+  { "sand.CRUMBLED.xpos",                              "1"                             },
+  { "sand.CRUMBLED.ypos",                              "0"                             },
+  { "sand.CRUMBLED.frames",                            "1"                             },
+  { "sand.digging.left",                               "RocksMore.png"                 },
+  { "sand.digging.left.xpos",                          "6"                             },
+  { "sand.digging.left.ypos",                          "3"                             },
+  { "sand.digging.left.frames",                                "3"                             },
+  { "sand.digging.left.delay",                         "2"                             },
+  { "sand.digging.left.anim_mode",                     "linear"                        },
+  { "sand.digging.right",                              "RocksMore.png"                 },
+  { "sand.digging.right.xpos",                         "9"                             },
+  { "sand.digging.right.ypos",                         "3"                             },
+  { "sand.digging.right.frames",                       "3"                             },
+  { "sand.digging.right.delay",                                "2"                             },
+  { "sand.digging.right.anim_mode",                    "linear"                        },
+  { "sand.digging.up",                                 "RocksMore.png"                 },
+  { "sand.digging.up.xpos",                            "0"                             },
+  { "sand.digging.up.ypos",                            "3"                             },
+  { "sand.digging.up.frames",                          "3"                             },
+  { "sand.digging.up.delay",                           "2"                             },
+  { "sand.digging.up.anim_mode",                       "linear"                        },
+  { "sand.digging.down",                               "RocksMore.png"                 },
+  { "sand.digging.down.xpos",                          "3"                             },
+  { "sand.digging.down.ypos",                          "3"                             },
+  { "sand.digging.down.frames",                                "3"                             },
+  { "sand.digging.down.delay",                         "2"                             },
+  { "sand.digging.down.anim_mode",                     "linear"                        },
+  { "sand.digging.left.CRUMBLED",                      "RocksMore.png"                 },
+  { "sand.digging.left.CRUMBLED.xpos",                 "6"                             },
+  { "sand.digging.left.CRUMBLED.ypos",                 "0"                             },
+  { "sand.digging.left.CRUMBLED.frames",               "3"                             },
+  { "sand.digging.left.CRUMBLED.delay",                        "2"                             },
+  { "sand.digging.left.CRUMBLED.anim_mode",            "linear"                        },
+  { "sand.digging.right.CRUMBLED",                     "RocksMore.png"                 },
+  { "sand.digging.right.CRUMBLED.xpos",                        "9"                             },
+  { "sand.digging.right.CRUMBLED.ypos",                        "0"                             },
+  { "sand.digging.right.CRUMBLED.frames",              "3"                             },
+  { "sand.digging.right.CRUMBLED.delay",               "2"                             },
+  { "sand.digging.right.CRUMBLED.anim_mode",           "linear"                        },
+  { "sand.digging.up.CRUMBLED",                                "RocksMore.png"                 },
+  { "sand.digging.up.CRUMBLED.xpos",                   "0"                             },
+  { "sand.digging.up.CRUMBLED.ypos",                   "0"                             },
+  { "sand.digging.up.CRUMBLED.frames",                 "3"                             },
+  { "sand.digging.up.CRUMBLED.delay",                  "2"                             },
+  { "sand.digging.up.CRUMBLED.anim_mode",              "linear"                        },
+  { "sand.digging.down.CRUMBLED",                      "RocksMore.png"                 },
+  { "sand.digging.down.CRUMBLED.xpos",                 "3"                             },
+  { "sand.digging.down.CRUMBLED.ypos",                 "0"                             },
+  { "sand.digging.down.CRUMBLED.frames",               "3"                             },
+  { "sand.digging.down.CRUMBLED.delay",                        "2"                             },
+  { "sand.digging.down.CRUMBLED.anim_mode",            "linear"                        },
+
+  { "wall",                                            "RocksElements.png"             },
+  { "wall.xpos",                                       "5"                             },
+  { "wall.ypos",                                       "0"                             },
+  { "wall.frames",                                     "1"                             },
+
+  { "wall_slippery",                                   "RocksElements.png"             },
+  { "wall_slippery.xpos",                              "6"                             },
+  { "wall_slippery.ypos",                              "0"                             },
+  { "wall_slippery.frames",                            "1"                             },
+
+  { "steelwall",                                       "RocksElements.png"             },
+  { "steelwall.xpos",                                  "4"                             },
+  { "steelwall.ypos",                                  "0"                             },
+  { "steelwall.frames",                                        "1"                             },
+
+  { "rock",                                            "RocksElements.png"             },
+  { "rock.xpos",                                       "12"                            },
+  { "rock.ypos",                                       "0"                             },
+  { "rock.frames",                                     "1"                             },
+  { "rock.moving.left",                                        "RocksElements.png"             },
+  { "rock.moving.left.xpos",                           "12"                            },
+  { "rock.moving.left.ypos",                           "0"                             },
+  { "rock.moving.left.frames",                         "4"                             },
+  { "rock.moving.left.delay",                          "2"                             },
+  { "rock.moving.left.anim_mode",                      "reverse"                       },
+  { "rock.moving.right",                               "RocksElements.png"             },
+  { "rock.moving.right.xpos",                          "12"                            },
+  { "rock.moving.right.ypos",                          "0"                             },
+  { "rock.moving.right.frames",                                "4"                             },
+  { "rock.moving.right.start_frame",                   "1"                             },
+  { "rock.moving.right.delay",                         "2"                             },
+  { "rock.pushing.left",                               "RocksElements.png"             },
+  { "rock.pushing.left.xpos",                          "12"                            },
+  { "rock.pushing.left.ypos",                          "0"                             },
+  { "rock.pushing.left.frames",                                "4"                             },
+  { "rock.pushing.left.delay",                         "2"                             },
+  { "rock.pushing.left.anim_mode",                     "reverse"                       },
+  { "rock.pushing.right",                              "RocksElements.png"             },
+  { "rock.pushing.right.xpos",                         "12"                            },
+  { "rock.pushing.right.ypos",                         "0"                             },
+  { "rock.pushing.right.frames",                       "4"                             },
+  { "rock.pushing.right.start_frame",                  "1"                             },
+  { "rock.pushing.right.delay",                                "2"                             },
+
+  { "emerald",                                         "RocksElements.png"             },
+  { "emerald.xpos",                                    "8"                             },
+  { "emerald.ypos",                                    "0"                             },
+  { "emerald.frames",                                  "1"                             },
+  { "emerald.moving",                                  "RocksElements.png"             },
+  { "emerald.moving.xpos",                             "8"                             },
+  { "emerald.moving.ypos",                             "0"                             },
+  { "emerald.moving.frames",                           "2"                             },
+  { "emerald.moving.delay",                            "4"                             },
+  { "emerald.falling",                                 "RocksElements.png"             },
+  { "emerald.falling.xpos",                            "8"                             },
+  { "emerald.falling.ypos",                            "0"                             },
+  { "emerald.falling.frames",                          "2"                             },
+  { "emerald.falling.delay",                           "4"                             },
+  { "emerald.collecting",                              "RocksCollect.png"              },
+  { "emerald.collecting.xpos",                         "0"                             },
+  { "emerald.collecting.ypos",                         "0"                             },
+  { "emerald.collecting.frames",                       "7"                             },
+  { "emerald.collecting.anim_mode",                    "linear"                        },
+
+  { "diamond",                                         "RocksElements.png"             },
+  { "diamond.xpos",                                    "10"                            },
+  { "diamond.ypos",                                    "0"                             },
+  { "diamond.frames",                                  "1"                             },
+  { "diamond.moving",                                  "RocksElements.png"             },
+  { "diamond.moving.xpos",                             "10"                            },
+  { "diamond.moving.ypos",                             "0"                             },
+  { "diamond.moving.frames",                           "2"                             },
+  { "diamond.moving.delay",                            "4"                             },
+  { "diamond.falling",                                 "RocksElements.png"             },
+  { "diamond.falling.xpos",                            "10"                            },
+  { "diamond.falling.ypos",                            "0"                             },
+  { "diamond.falling.frames",                          "2"                             },
+  { "diamond.falling.delay",                           "4"                             },
+  { "diamond.collecting",                              "RocksCollect.png"              },
+  { "diamond.collecting.xpos",                         "0"                             },
+  { "diamond.collecting.ypos",                         "1"                             },
+  { "diamond.collecting.frames",                       "7"                             },
+  { "diamond.collecting.anim_mode",                    "linear"                        },
+
+  { "bomb",                                            "RocksElements.png"             },
+  { "bomb.xpos",                                       "11"                            },
+  { "bomb.ypos",                                       "1"                             },
+  { "bomb.frames",                                     "1"                             },
+
+  { "nut",                                             "RocksElements.png"             },
+  { "nut.xpos",                                                "12"                            },
+  { "nut.ypos",                                                "1"                             },
+  { "nut.frames",                                      "1"                             },
+  { "nut.breaking",                                    "RocksElements.png"             },
+  { "nut.breaking.xpos",                               "13"                            },
+  { "nut.breaking.ypos",                               "1"                             },
+  { "nut.breaking.frames",                             "3"                             },
+  { "nut.breaking.delay",                              "2"                             },
+  { "nut.breaking.anim_mode",                          "linear"                        },
+
+  { "dynamite",                                                "RocksElements.png"             },
+  { "dynamite.xpos",                                   "0"                             },
+  { "dynamite.ypos",                                   "3"                             },
+  { "dynamite.frames",                                 "1"                             },
+  { "dynamite.active",                                 "RocksElements.png"             },
+  { "dynamite.active.xpos",                            "1"                             },
+  { "dynamite.active.ypos",                            "3"                             },
+  { "dynamite.active.frames",                          "7"                             },
+  { "dynamite.active.delay",                           "12"                            },
+  { "dynamite.active.anim_mode",                       "linear"                        },
+  { "dynamite.collecting",                             "RocksCollect.png"              },
+  { "dynamite.collecting.xpos",                                "0"                             },
+  { "dynamite.collecting.ypos",                                "7"                             },
+  { "dynamite.collecting.frames",                      "7"                             },
+  { "dynamite.collecting.anim_mode",                   "linear"                        },
+
+  { "em_dynamite",                                     "RocksEMC.png"                  },
+  { "em_dynamite.xpos",                                        "0"                             },
+  { "em_dynamite.ypos",                                        "15"                            },
+  { "em_dynamite.frames",                              "1"                             },
+  { "em_dynamite.active",                              "RocksEMC.png"                  },
+  { "em_dynamite.active.xpos",                         "1"                             },
+  { "em_dynamite.active.ypos",                         "15"                            },
+  { "em_dynamite.active.frames",                       "4"                             },
+  { "em_dynamite.active.delay",                                "8"                             },
+  { "em_dynamite.active.anim_mode",                    "linear"                        },
+  { "em_dynamite.active.EDITOR",                       "RocksEMC.png"                  },
+  { "em_dynamite.active.EDITOR.xpos",                  "2"                             },
+  { "em_dynamite.active.EDITOR.ypos",                  "15"                            },
+  { "em_dynamite.collecting",                          "RocksCollect.png"              },
+  { "em_dynamite.collecting.xpos",                     "0"                             },
+  { "em_dynamite.collecting.ypos",                     "15"                            },
+  { "em_dynamite.collecting.frames",                   "7"                             },
+  { "em_dynamite.collecting.anim_mode",                        "linear"                        },
+
+  { "wall_emerald",                                    "RocksElements.png"             },
+  { "wall_emerald.xpos",                               "4"                             },
+  { "wall_emerald.ypos",                               "8"                             },
+  { "wall_emerald.frames",                             "1"                             },
+
+  { "wall_diamond",                                    "RocksElements.png"             },
+  { "wall_diamond.xpos",                               "5"                             },
+  { "wall_diamond.ypos",                               "8"                             },
+  { "wall_diamond.frames",                             "1"                             },
+
+  { "bug",                                             "RocksElements.png"             },
+  { "bug.xpos",                                                "8"                             },
+  { "bug.ypos",                                                "4"                             },
+  { "bug.frames",                                      "4"                             },
+  { "bug.delay",                                       "8"                             },
+  { "bug.right",                                       "RocksElements.png"             },
+  { "bug.right.xpos",                                  "8"                             },
+  { "bug.right.ypos",                                  "4"                             },
+  { "bug.right.frames",                                        "1"                             },
+  { "bug.up",                                          "RocksElements.png"             },
+  { "bug.up.xpos",                                     "9"                             },
+  { "bug.up.ypos",                                     "4"                             },
+  { "bug.up.frames",                                   "1"                             },
+  { "bug.left",                                                "RocksElements.png"             },
+  { "bug.left.xpos",                                   "10"                            },
+  { "bug.left.ypos",                                   "4"                             },
+  { "bug.left.frames",                                 "1"                             },
+  { "bug.down",                                                "RocksElements.png"             },
+  { "bug.down.xpos",                                   "11"                            },
+  { "bug.down.ypos",                                   "4"                             },
+  { "bug.down.frames",                                 "1"                             },
+  { "bug.moving.right",                                        "RocksElements.png"             },
+  { "bug.moving.right.xpos",                           "8"                             },
+  { "bug.moving.right.ypos",                           "4"                             },
+  { "bug.moving.right.frames",                         "2"                             },
+  { "bug.moving.right.delay",                          "4"                             },
+  { "bug.moving.right.offset",                         "128"                           },
+  { "bug.moving.up",                                   "RocksElements.png"             },
+  { "bug.moving.up.xpos",                              "9"                             },
+  { "bug.moving.up.ypos",                              "4"                             },
+  { "bug.moving.up.frames",                            "2"                             },
+  { "bug.moving.up.delay",                             "4"                             },
+  { "bug.moving.up.offset",                            "128"                           },
+  { "bug.moving.left",                                 "RocksElements.png"             },
+  { "bug.moving.left.xpos",                            "10"                            },
+  { "bug.moving.left.ypos",                            "4"                             },
+  { "bug.moving.left.frames",                          "2"                             },
+  { "bug.moving.left.delay",                           "4"                             },
+  { "bug.moving.left.offset",                          "128"                           },
+  { "bug.moving.down",                                 "RocksElements.png"             },
+  { "bug.moving.down.xpos",                            "11"                            },
+  { "bug.moving.down.ypos",                            "4"                             },
+  { "bug.moving.down.frames",                          "2"                             },
+  { "bug.moving.down.delay",                           "4"                             },
+  { "bug.moving.down.offset",                          "128"                           },
+  { "bug.turning_from_right.up",                       "RocksMore.png"                 },
+  { "bug.turning_from_right.up.xpos",                  "0"                             },
+  { "bug.turning_from_right.up.ypos",                  "6"                             },
+  { "bug.turning_from_right.up.frames",                        "4"                             },
+  { "bug.turning_from_right.up.delay",                 "2"                             },
+  { "bug.turning_from_right.up.anim_mode",             "linear,reverse"                },
+  { "bug.turning_from_up.left",                                "RocksMore.png"                 },
+  { "bug.turning_from_up.left.xpos",                   "12"                            },
+  { "bug.turning_from_up.left.ypos",                   "6"                             },
+  { "bug.turning_from_up.left.frames",                 "4"                             },
+  { "bug.turning_from_up.left.delay",                  "2"                             },
+  { "bug.turning_from_up.left.anim_mode",              "linear,reverse"                },
+  { "bug.turning_from_left.down",                      "RocksMore.png"                 },
+  { "bug.turning_from_left.down.xpos",                 "8"                             },
+  { "bug.turning_from_left.down.ypos",                 "6"                             },
+  { "bug.turning_from_left.down.frames",               "4"                             },
+  { "bug.turning_from_left.down.delay",                        "2"                             },
+  { "bug.turning_from_left.down.anim_mode",            "linear,reverse"                },
+  { "bug.turning_from_down.right",                     "RocksMore.png"                 },
+  { "bug.turning_from_down.right.xpos",                        "4"                             },
+  { "bug.turning_from_down.right.ypos",                        "6"                             },
+  { "bug.turning_from_down.right.frames",              "4"                             },
+  { "bug.turning_from_down.right.delay",               "2"                             },
+  { "bug.turning_from_down.right.anim_mode",           "linear,reverse"                },
+  { "bug.turning_from_right.down",                     "RocksMore.png"                 },
+  { "bug.turning_from_right.down.xpos",                        "5"                             },
+  { "bug.turning_from_right.down.ypos",                        "6"                             },
+  { "bug.turning_from_right.down.frames",              "4"                             },
+  { "bug.turning_from_right.down.delay",               "2"                             },
+  { "bug.turning_from_right.down.anim_mode",           "linear"                        },
+  { "bug.turning_from_up.right",                       "RocksMore.png"                 },
+  { "bug.turning_from_up.right.xpos",                  "1"                             },
+  { "bug.turning_from_up.right.ypos",                  "6"                             },
+  { "bug.turning_from_up.right.frames",                        "4"                             },
+  { "bug.turning_from_up.right.delay",                 "2"                             },
+  { "bug.turning_from_up.right.anim_mode",             "linear"                        },
+  { "bug.turning_from_left.up",                                "RocksMore.png"                 },
+  { "bug.turning_from_left.up.xpos",                   "13"                            },
+  { "bug.turning_from_left.up.ypos",                   "6"                             },
+  { "bug.turning_from_left.up.frames",                 "4"                             },
+  { "bug.turning_from_left.up.delay",                  "2"                             },
+  { "bug.turning_from_left.up.anim_mode",              "linear"                        },
+  { "bug.turning_from_down.left",                      "RocksMore.png"                 },
+  { "bug.turning_from_down.left.xpos",                 "9"                             },
+  { "bug.turning_from_down.left.ypos",                 "6"                             },
+  { "bug.turning_from_down.left.frames",               "4"                             },
+  { "bug.turning_from_down.left.delay",                        "2"                             },
+  { "bug.turning_from_down.left.anim_mode",            "linear"                        },
+
+  { "spaceship",                                       "RocksElements.png"             },
+  { "spaceship.xpos",                                  "8"                             },
+  { "spaceship.ypos",                                  "3"                             },
+  { "spaceship.frames",                                        "4"                             },
+  { "spaceship.delay",                                 "8"                             },
+  { "spaceship.right",                                 "RocksElements.png"             },
+  { "spaceship.right.xpos",                            "8"                             },
+  { "spaceship.right.ypos",                            "3"                             },
+  { "spaceship.right.frames",                          "1"                             },
+  { "spaceship.up",                                    "RocksElements.png"             },
+  { "spaceship.up.xpos",                               "9"                             },
+  { "spaceship.up.ypos",                               "3"                             },
+  { "spaceship.up.frames",                             "1"                             },
+  { "spaceship.left",                                  "RocksElements.png"             },
+  { "spaceship.left.xpos",                             "10"                            },
+  { "spaceship.left.ypos",                             "3"                             },
+  { "spaceship.left.frames",                           "1"                             },
+  { "spaceship.down",                                  "RocksElements.png"             },
+  { "spaceship.down.xpos",                             "11"                            },
+  { "spaceship.down.ypos",                             "3"                             },
+  { "spaceship.down.frames",                           "1"                             },
+  { "spaceship.moving.right",                          "RocksElements.png"             },
+  { "spaceship.moving.right.xpos",                     "8"                             },
+  { "spaceship.moving.right.ypos",                     "3"                             },
+  { "spaceship.moving.right.frames",                   "2"                             },
+  { "spaceship.moving.right.delay",                    "4"                             },
+  { "spaceship.moving.right.offset",                   "128"                           },
+  { "spaceship.moving.up",                             "RocksElements.png"             },
+  { "spaceship.moving.up.xpos",                                "9"                             },
+  { "spaceship.moving.up.ypos",                                "3"                             },
+  { "spaceship.moving.up.frames",                      "2"                             },
+  { "spaceship.moving.up.delay",                       "4"                             },
+  { "spaceship.moving.up.offset",                      "128"                           },
+  { "spaceship.moving.left",                           "RocksElements.png"             },
+  { "spaceship.moving.left.xpos",                      "10"                            },
+  { "spaceship.moving.left.ypos",                      "3"                             },
+  { "spaceship.moving.left.frames",                    "2"                             },
+  { "spaceship.moving.left.delay",                     "4"                             },
+  { "spaceship.moving.left.offset",                    "128"                           },
+  { "spaceship.moving.down",                           "RocksElements.png"             },
+  { "spaceship.moving.down.xpos",                      "11"                            },
+  { "spaceship.moving.down.ypos",                      "3"                             },
+  { "spaceship.moving.down.frames",                    "2"                             },
+  { "spaceship.moving.down.delay",                     "4"                             },
+  { "spaceship.moving.down.offset",                    "128"                           },
+  { "spaceship.turning_from_right.up",                 "RocksMore.png"                 },
+  { "spaceship.turning_from_right.up.xpos",            "0"                             },
+  { "spaceship.turning_from_right.up.ypos",            "5"                             },
+  { "spaceship.turning_from_right.up.frames",          "4"                             },
+  { "spaceship.turning_from_right.up.delay",           "2"                             },
+  { "spaceship.turning_from_right.up.anim_mode",       "linear,reverse"                },
+  { "spaceship.turning_from_up.left",                  "RocksMore.png"                 },
+  { "spaceship.turning_from_up.left.xpos",             "12"                            },
+  { "spaceship.turning_from_up.left.ypos",             "5"                             },
+  { "spaceship.turning_from_up.left.frames",           "4"                             },
+  { "spaceship.turning_from_up.left.delay",            "2"                             },
+  { "spaceship.turning_from_up.left.anim_mode",                "linear,reverse"                },
+  { "spaceship.turning_from_left.down",                        "RocksMore.png"                 },
+  { "spaceship.turning_from_left.down.xpos",           "8"                             },
+  { "spaceship.turning_from_left.down.ypos",           "5"                             },
+  { "spaceship.turning_from_left.down.frames",         "4"                             },
+  { "spaceship.turning_from_left.down.delay",          "2"                             },
+  { "spaceship.turning_from_left.down.anim_mode",      "linear,reverse"                },
+  { "spaceship.turning_from_down.right",               "RocksMore.png"                 },
+  { "spaceship.turning_from_down.right.xpos",          "4"                             },
+  { "spaceship.turning_from_down.right.ypos",          "5"                             },
+  { "spaceship.turning_from_down.right.frames",                "4"                             },
+  { "spaceship.turning_from_down.right.delay",         "2"                             },
+  { "spaceship.turning_from_down.right.anim_mode",     "linear,reverse"                },
+  { "spaceship.turning_from_right.down",               "RocksMore.png"                 },
+  { "spaceship.turning_from_right.down.xpos",          "5"                             },
+  { "spaceship.turning_from_right.down.ypos",          "5"                             },
+  { "spaceship.turning_from_right.down.frames",                "4"                             },
+  { "spaceship.turning_from_right.down.delay",         "2"                             },
+  { "spaceship.turning_from_right.down.anim_mode",     "linear"                        },
+  { "spaceship.turning_from_up.right",                 "RocksMore.png"                 },
+  { "spaceship.turning_from_up.right.xpos",            "1"                             },
+  { "spaceship.turning_from_up.right.ypos",            "5"                             },
+  { "spaceship.turning_from_up.right.frames",          "4"                             },
+  { "spaceship.turning_from_up.right.delay",           "2"                             },
+  { "spaceship.turning_from_up.right.anim_mode",       "linear"                        },
+  { "spaceship.turning_from_left.up",                  "RocksMore.png"                 },
+  { "spaceship.turning_from_left.up.xpos",             "13"                            },
+  { "spaceship.turning_from_left.up.ypos",             "5"                             },
+  { "spaceship.turning_from_left.up.frames",           "4"                             },
+  { "spaceship.turning_from_left.up.delay",            "2"                             },
+  { "spaceship.turning_from_left.up.anim_mode",                "linear"                        },
+  { "spaceship.turning_from_down.left",                        "RocksMore.png"                 },
+  { "spaceship.turning_from_down.left.xpos",           "9"                             },
+  { "spaceship.turning_from_down.left.ypos",           "5"                             },
+  { "spaceship.turning_from_down.left.frames",         "4"                             },
+  { "spaceship.turning_from_down.left.delay",          "2"                             },
+  { "spaceship.turning_from_down.left.anim_mode",      "linear"                        },
+
+  { "yamyam",                                          "RocksElements.png"             },
+  { "yamyam.xpos",                                     "0"                             },
+  { "yamyam.ypos",                                     "5"                             },
+  { "yamyam.frames",                                   "4"                             },
+  { "yamyam.anim_mode",                                        "pingpong2"                     },
+  { "yamyam.left",                                     "RocksElements.png"             },
+  { "yamyam.left.xpos",                                        "0"                             },
+  { "yamyam.left.ypos",                                        "5"                             },
+  { "yamyam.left.frames",                              "4"                             },
+  { "yamyam.left.anim_mode",                           "pingpong2"                     },
+  { "yamyam.left.EDITOR",                              "RocksEMC.png"                  },
+  { "yamyam.left.EDITOR.xpos",                         "7"                             },
+  { "yamyam.left.EDITOR.ypos",                         "15"                            },
+  { "yamyam.right",                                    "RocksElements.png"             },
+  { "yamyam.right.xpos",                               "0"                             },
+  { "yamyam.right.ypos",                               "5"                             },
+  { "yamyam.right.frames",                             "4"                             },
+  { "yamyam.right.anim_mode",                          "pingpong2"                     },
+  { "yamyam.right.EDITOR",                             "RocksEMC.png"                  },
+  { "yamyam.right.EDITOR.xpos",                                "8"                             },
+  { "yamyam.right.EDITOR.ypos",                                "15"                            },
+  { "yamyam.up",                                       "RocksElements.png"             },
+  { "yamyam.up.xpos",                                  "0"                             },
+  { "yamyam.up.ypos",                                  "5"                             },
+  { "yamyam.up.frames",                                        "4"                             },
+  { "yamyam.up.anim_mode",                             "pingpong2"                     },
+  { "yamyam.up.EDITOR",                                        "RocksEMC.png"                  },
+  { "yamyam.up.EDITOR.xpos",                           "5"                             },
+  { "yamyam.up.EDITOR.ypos",                           "15"                            },
+  { "yamyam.down",                                     "RocksElements.png"             },
+  { "yamyam.down.xpos",                                        "0"                             },
+  { "yamyam.down.ypos",                                        "5"                             },
+  { "yamyam.down.frames",                              "4"                             },
+  { "yamyam.down.anim_mode",                           "pingpong2"                     },
+  { "yamyam.down.EDITOR",                              "RocksEMC.png"                  },
+  { "yamyam.down.EDITOR.xpos",                         "6"                             },
+  { "yamyam.down.EDITOR.ypos",                         "15"                            },
+  { "yamyam.moving",                                   "RocksElements.png"             },
+  { "yamyam.moving.xpos",                              "0"                             },
+  { "yamyam.moving.ypos",                              "5"                             },
+  { "yamyam.moving.frames",                            "1"                             },
+
+  { "robot",                                           "RocksElements.png"             },
+  { "robot.xpos",                                      "4"                             },
+  { "robot.ypos",                                      "5"                             },
+  { "robot.frames",                                    "4"                             },
+  { "robot.anim_mode",                                 "pingpong2"                     },
+  { "robot.moving",                                    "RocksElements.png"             },
+  { "robot.moving.xpos",                               "4"                             },
+  { "robot.moving.ypos",                               "5"                             },
+  { "robot.moving.frames",                             "1"                             },
+
+  { "robot_wheel",                                     "RocksElements.png"             },
+  { "robot_wheel.xpos",                                        "0"                             },
+  { "robot_wheel.ypos",                                        "6"                             },
+  { "robot_wheel.frames",                              "1"                             },
+  { "robot_wheel.active",                              "RocksElements.png"             },
+  { "robot_wheel.active.xpos",                         "0"                             },
+  { "robot_wheel.active.ypos",                         "6"                             },
+  { "robot_wheel.active.frames",                       "4"                             },
+
+  { "magic_wall",                                      "RocksElements.png"             },
+  { "magic_wall.xpos",                                 "0"                             },
+  { "magic_wall.ypos",                                 "8"                             },
+  { "magic_wall.frames",                               "1"                             },
+  { "magic_wall.active",                               "RocksElements.png"             },
+  { "magic_wall.active.xpos",                          "0"                             },
+  { "magic_wall.active.ypos",                          "8"                             },
+  { "magic_wall.active.frames",                                "4"                             },
+  { "magic_wall.active.anim_mode",                     "reverse"                       },
+  { "magic_wall.active.delay",                         "4"                             },
+  { "magic_wall.active.global_sync",                   "true"                          },
+  { "magic_wall.filling",                              "RocksElements.png"             },
+  { "magic_wall.filling.xpos",                         "0"                             },
+  { "magic_wall.filling.ypos",                         "8"                             },
+  { "magic_wall.filling.frames",                       "4"                             },
+  { "magic_wall.filling.anim_mode",                    "reverse"                       },
+  { "magic_wall.filling.delay",                                "4"                             },
+  { "magic_wall.filling.global_sync",                  "true"                          },
+  { "magic_wall_full",                                 "RocksElements.png"             },
+  { "magic_wall_full.xpos",                            "0"                             },
+  { "magic_wall_full.ypos",                            "8"                             },
+  { "magic_wall_full.frames",                          "4"                             },
+  { "magic_wall_full.anim_mode",                       "reverse"                       },
+  { "magic_wall_full.delay",                           "4"                             },
+  { "magic_wall_full.global_sync",                     "true"                          },
+  { "magic_wall.emptying",                             "RocksElements.png"             },
+  { "magic_wall.emptying.xpos",                                "0"                             },
+  { "magic_wall.emptying.ypos",                                "8"                             },
+  { "magic_wall.emptying.frames",                      "4"                             },
+  { "magic_wall.emptying.anim_mode",                   "reverse"                       },
+  { "magic_wall.emptying.delay",                       "4"                             },
+  { "magic_wall.emptying.global_sync",                 "true"                          },
+  { "magic_wall_dead",                                 "RocksElements.png"             },
+  { "magic_wall_dead.xpos",                            "0"                             },
+  { "magic_wall_dead.ypos",                            "8"                             },
+  { "magic_wall_dead.frames",                          "1"                             },
+
+  { "dc_magic_wall",                                   "RocksDC2.png"                  },
+  { "dc_magic_wall.xpos",                              "0"                             },
+  { "dc_magic_wall.ypos",                              "3"                             },
+  { "dc_magic_wall.frames",                            "1"                             },
+  { "dc_magic_wall.active",                            "RocksDC2.png"                  },
+  { "dc_magic_wall.active.xpos",                       "0"                             },
+  { "dc_magic_wall.active.ypos",                       "3"                             },
+  { "dc_magic_wall.active.frames",                     "4"                             },
+  { "dc_magic_wall.active.anim_mode",                  "reverse"                       },
+  { "dc_magic_wall.active.delay",                      "4"                             },
+  { "dc_magic_wall.active.global_sync",                        "true"                          },
+  { "dc_magic_wall.filling",                           "RocksDC2.png"                  },
+  { "dc_magic_wall.filling.xpos",                      "0"                             },
+  { "dc_magic_wall.filling.ypos",                      "3"                             },
+  { "dc_magic_wall.filling.frames",                    "4"                             },
+  { "dc_magic_wall.filling.anim_mode",                 "reverse"                       },
+  { "dc_magic_wall.filling.delay",                     "4"                             },
+  { "dc_magic_wall.filling.global_sync",               "true"                          },
+  { "dc_magic_wall_full",                              "RocksDC2.png"                  },
+  { "dc_magic_wall_full.xpos",                         "0"                             },
+  { "dc_magic_wall_full.ypos",                         "3"                             },
+  { "dc_magic_wall_full.frames",                       "4"                             },
+  { "dc_magic_wall_full.anim_mode",                    "reverse"                       },
+  { "dc_magic_wall_full.delay",                                "4"                             },
+  { "dc_magic_wall_full.global_sync",                  "true"                          },
+  { "dc_magic_wall.emptying",                          "RocksDC2.png"                  },
+  { "dc_magic_wall.emptying.xpos",                     "0"                             },
+  { "dc_magic_wall.emptying.ypos",                     "3"                             },
+  { "dc_magic_wall.emptying.frames",                   "4"                             },
+  { "dc_magic_wall.emptying.anim_mode",                        "reverse"                       },
+  { "dc_magic_wall.emptying.delay",                    "4"                             },
+  { "dc_magic_wall.emptying.global_sync",              "true"                          },
+  { "dc_magic_wall_dead",                              "RocksDC2.png"                  },
+  { "dc_magic_wall_dead.xpos",                         "0"                             },
+  { "dc_magic_wall_dead.ypos",                         "3"                             },
+  { "dc_magic_wall_dead.frames",                       "1"                             },
+
+  { "quicksand_empty",                                 "RocksElements.png"             },
+  { "quicksand_empty.xpos",                            "2"                             },
+  { "quicksand_empty.ypos",                            "0"                             },
+  { "quicksand_empty.frames",                          "1"                             },
+  { "quicksand.filling",                               "RocksElements.png"             },
+  { "quicksand.filling.xpos",                          "3"                             },
+  { "quicksand.filling.ypos",                          "0"                             },
+  { "quicksand.filling.frames",                                "1"                             },
+  { "quicksand_full",                                  "RocksElements.png"             },
+  { "quicksand_full.xpos",                             "3"                             },
+  { "quicksand_full.ypos",                             "0"                             },
+  { "quicksand_full.frames",                           "1"                             },
+  { "quicksand_full.EDITOR",                           "RocksElements.png"             },
+  { "quicksand_full.EDITOR.xpos",                      "3"                             },
+  { "quicksand_full.EDITOR.ypos",                      "14"                            },
+  { "quicksand.emptying",                              "RocksElements.png"             },
+  { "quicksand.emptying.xpos",                         "3"                             },
+  { "quicksand.emptying.ypos",                         "0"                             },
+  { "quicksand.emptying.frames",                       "1"                             },
+
+  { "quicksand_fast_empty",                            "RocksDC2.png"                  },
+  { "quicksand_fast_empty.xpos",                       "4"                             },
+  { "quicksand_fast_empty.ypos",                       "3"                             },
+  { "quicksand_fast_empty.frames",                     "1"                             },
+  { "quicksand_fast.filling",                          "RocksDC2.png"                  },
+  { "quicksand_fast.filling.xpos",                     "4"                             },
+  { "quicksand_fast.filling.ypos",                     "3"                             },
+  { "quicksand_fast.filling.frames",                   "1"                             },
+  { "quicksand_fast_full",                             "RocksDC2.png"                  },
+  { "quicksand_fast_full.xpos",                                "4"                             },
+  { "quicksand_fast_full.ypos",                                "3"                             },
+  { "quicksand_fast_full.frames",                      "1"                             },
+  { "quicksand_fast_full.EDITOR",                      "RocksDC2.png"                  },
+  { "quicksand_fast_full.EDITOR.xpos",                 "5"                             },
+  { "quicksand_fast_full.EDITOR.ypos",                 "3"                             },
+  { "quicksand_fast.emptying",                         "RocksDC2.png"                  },
+  { "quicksand_fast.emptying.xpos",                    "4"                             },
+  { "quicksand_fast.emptying.ypos",                    "3"                             },
+  { "quicksand_fast.emptying.frames",                  "1"                             },
+
+  { "acid_pool_topleft",                               "RocksElements.png"             },
+  { "acid_pool_topleft.xpos",                          "0"                             },
+  { "acid_pool_topleft.ypos",                          "1"                             },
+  { "acid_pool_topleft.frames",                                "1"                             },
+  { "acid_pool_topright",                              "RocksElements.png"             },
+  { "acid_pool_topright.xpos",                         "2"                             },
+  { "acid_pool_topright.ypos",                         "1"                             },
+  { "acid_pool_topright.frames",                       "1"                             },
+  { "acid_pool_bottomleft",                            "RocksElements.png"             },
+  { "acid_pool_bottomleft.xpos",                       "0"                             },
+  { "acid_pool_bottomleft.ypos",                       "2"                             },
+  { "acid_pool_bottomleft.frames",                     "1"                             },
+  { "acid_pool_bottom",                                        "RocksElements.png"             },
+  { "acid_pool_bottom.xpos",                           "1"                             },
+  { "acid_pool_bottom.ypos",                           "2"                             },
+  { "acid_pool_bottom.frames",                         "1"                             },
+  { "acid_pool_bottomright",                           "RocksElements.png"             },
+  { "acid_pool_bottomright.xpos",                      "2"                             },
+  { "acid_pool_bottomright.ypos",                      "2"                             },
+  { "acid_pool_bottomright.frames",                    "1"                             },
+
+  { "acid",                                            "RocksElements.png"             },
+  { "acid.xpos",                                       "12"                            },
+  { "acid.ypos",                                       "7"                             },
+  { "acid.frames",                                     "4"                             },
+  { "acid.delay",                                      "10"                            },
+  { "acid.global_sync",                                        "true"                          },
+
+  { "acid_splash_left",                                        "RocksHeroes.png"               },
+  { "acid_splash_left.xpos",                           "8"                             },
+  { "acid_splash_left.ypos",                           "10"                            },
+  { "acid_splash_left.frames",                         "4"                             },
+  { "acid_splash_left.delay",                          "2"                             },
+  { "acid_splash_left.anim_mode",                      "linear"                        },
+  { "acid_splash_right",                               "RocksHeroes.png"               },
+  { "acid_splash_right.xpos",                          "12"                            },
+  { "acid_splash_right.ypos",                          "10"                            },
+  { "acid_splash_right.frames",                                "4"                             },
+  { "acid_splash_right.delay",                         "2"                             },
+  { "acid_splash_right.anim_mode",                     "linear"                        },
+
+  { "amoeba_drop",                                     "RocksElements.png"             },
+  { "amoeba_drop.xpos",                                        "5"                             },
+  { "amoeba_drop.ypos",                                        "6"                             },
+  { "amoeba_drop.frames",                              "1"                             },
+  { "amoeba.growing",                                  "RocksElements.png"             },
+  { "amoeba.growing.xpos",                             "5"                             },
+  { "amoeba.growing.ypos",                             "6"                             },
+  { "amoeba.growing.frames",                           "3"                             },
+  { "amoeba.growing.delay",                            "2"                             },
+  { "amoeba.growing.anim_mode",                                "linear"                        },
+  { "amoeba.shrinking",                                        "RocksElements.png"             },
+  { "amoeba.shrinking.xpos",                           "5"                             },
+  { "amoeba.shrinking.ypos",                           "6"                             },
+  { "amoeba.shrinking.frames",                         "3"                             },
+  { "amoeba.shrinking.delay",                          "2"                             },
+  { "amoeba.shrinking.anim_mode",                      "linear,reverse"                },
+  { "amoeba_wet",                                      "RocksElements.png"             },
+  { "amoeba_wet.xpos",                                 "8"                             },
+  { "amoeba_wet.ypos",                                 "6"                             },
+  { "amoeba_wet.frames",                               "4"                             },
+  { "amoeba_wet.anim_mode",                            "random_static"                 },
+  { "amoeba_wet.EDITOR",                               "RocksElements.png"             },
+  { "amoeba_wet.EDITOR.xpos",                          "4"                             },
+  { "amoeba_wet.EDITOR.ypos",                          "6"                             },
+  { "amoeba.dropping",                                 "RocksElements.png"             },
+  { "amoeba.dropping.xpos",                            "8"                             },
+  { "amoeba.dropping.ypos",                            "6"                             },
+  { "amoeba.dropping.frames",                          "4"                             },
+  { "amoeba.dropping.anim_mode",                       "random_static"                 },
+  { "amoeba_dry",                                      "RocksElements.png"             },
+  { "amoeba_dry.xpos",                                 "8"                             },
+  { "amoeba_dry.ypos",                                 "6"                             },
+  { "amoeba_dry.frames",                               "4"                             },
+  { "amoeba_dry.anim_mode",                            "random_static"                 },
+  { "amoeba_full",                                     "RocksElements.png"             },
+  { "amoeba_full.xpos",                                        "8"                             },
+  { "amoeba_full.ypos",                                        "6"                             },
+  { "amoeba_full.frames",                              "4"                             },
+  { "amoeba_full.anim_mode",                           "random_static"                 },
+  { "amoeba_full.EDITOR",                              "RocksElements.png"             },
+  { "amoeba_full.EDITOR.xpos",                         "8"                             },
+  { "amoeba_full.EDITOR.ypos",                         "7"                             },
+  { "amoeba_dead",                                     "RocksElements.png"             },
+  { "amoeba_dead.xpos",                                        "12"                            },
+  { "amoeba_dead.ypos",                                        "6"                             },
+  { "amoeba_dead.frames",                              "4"                             },
+  { "amoeba_dead.anim_mode",                           "random_static"                 },
+  { "amoeba_dead.EDITOR",                              "RocksElements.png"             },
+  { "amoeba_dead.EDITOR.xpos",                         "12"                            },
+  { "amoeba_dead.EDITOR.ypos",                         "6"                             },
+
+  { "em_key_1",                                                "RocksSP.png"                   },
+  { "em_key_1.xpos",                                   "4"                             },
+  { "em_key_1.ypos",                                   "6"                             },
+  { "em_key_1.frames",                                 "1"                             },
+  { "em_key_1.collecting",                             "RocksCollect.png"              },
+  { "em_key_1.collecting.xpos",                                "7"                             },
+  { "em_key_1.collecting.ypos",                                "4"                             },
+  { "em_key_1.collecting.frames",                      "7"                             },
+  { "em_key_1.collecting.anim_mode",                   "linear"                        },
+  { "em_key_2",                                                "RocksSP.png"                   },
+  { "em_key_2.xpos",                                   "5"                             },
+  { "em_key_2.ypos",                                   "6"                             },
+  { "em_key_2.frames",                                 "1"                             },
+  { "em_key_2.collecting",                             "RocksCollect.png"              },
+  { "em_key_2.collecting.xpos",                                "7"                             },
+  { "em_key_2.collecting.ypos",                                "5"                             },
+  { "em_key_2.collecting.frames",                      "7"                             },
+  { "em_key_2.collecting.anim_mode",                   "linear"                        },
+  { "em_key_3",                                                "RocksSP.png"                   },
+  { "em_key_3.xpos",                                   "6"                             },
+  { "em_key_3.ypos",                                   "6"                             },
+  { "em_key_3.frames",                                 "1"                             },
+  { "em_key_3.collecting",                             "RocksCollect.png"              },
+  { "em_key_3.collecting.xpos",                                "7"                             },
+  { "em_key_3.collecting.ypos",                                "6"                             },
+  { "em_key_3.collecting.frames",                      "7"                             },
+  { "em_key_3.collecting.anim_mode",                   "linear"                        },
+  { "em_key_4",                                                "RocksSP.png"                   },
+  { "em_key_4.xpos",                                   "7"                             },
+  { "em_key_4.ypos",                                   "6"                             },
+  { "em_key_4.frames",                                 "1"                             },
+  { "em_key_4.collecting",                             "RocksCollect.png"              },
+  { "em_key_4.collecting.xpos",                                "7"                             },
+  { "em_key_4.collecting.ypos",                                "7"                             },
+  { "em_key_4.collecting.frames",                      "7"                             },
+  { "em_key_4.collecting.anim_mode",                   "linear"                        },
+
+  { "dc_key_white",                                    "RocksSP.png"                   },
+  { "dc_key_white.xpos",                               "13"                            },
+  { "dc_key_white.ypos",                               "1"                             },
+  { "dc_key_white.frames",                             "1"                             },
+  { "dc_key_white.collecting",                         "RocksCollect.png"              },
+  { "dc_key_white.collecting.xpos",                    "7"                             },
+  { "dc_key_white.collecting.ypos",                    "0"                             },
+  { "dc_key_white.collecting.frames",                  "7"                             },
+  { "dc_key_white.collecting.anim_mode",               "linear"                        },
+
+  { "em_gate_1",                                       "RocksSP.png"                   },
+  { "em_gate_1.xpos",                                  "0"                             },
+  { "em_gate_1.ypos",                                  "7"                             },
+  { "em_gate_1.frames",                                        "1"                             },
+  { "em_gate_2",                                       "RocksSP.png"                   },
+  { "em_gate_2.xpos",                                  "1"                             },
+  { "em_gate_2.ypos",                                  "7"                             },
+  { "em_gate_2.frames",                                        "1"                             },
+  { "em_gate_3",                                       "RocksSP.png"                   },
+  { "em_gate_3.xpos",                                  "2"                             },
+  { "em_gate_3.ypos",                                  "7"                             },
+  { "em_gate_3.frames",                                        "1"                             },
+  { "em_gate_4",                                       "RocksSP.png"                   },
+  { "em_gate_4.xpos",                                  "3"                             },
+  { "em_gate_4.ypos",                                  "7"                             },
+  { "em_gate_4.frames",                                        "1"                             },
+
+  { "dc_gate_white",                                   "RocksSP.png"                   },
+  { "dc_gate_white.xpos",                              "14"                            },
+  { "dc_gate_white.ypos",                              "1"                             },
+  { "dc_gate_white.frames",                            "1"                             },
+
+  { "em_gate_1_gray",                                  "RocksSP.png"                   },
+  { "em_gate_1_gray.xpos",                             "4"                             },
+  { "em_gate_1_gray.ypos",                             "7"                             },
+  { "em_gate_1_gray.frames",                           "1"                             },
+  { "em_gate_1_gray.EDITOR",                           "RocksSP.png"                   },
+  { "em_gate_1_gray.EDITOR.xpos",                      "12"                            },
+  { "em_gate_1_gray.EDITOR.ypos",                      "11"                            },
+  { "em_gate_1_gray.active",                           "RocksSP.png"                   },
+  { "em_gate_1_gray.active.xpos",                      "0"                             },
+  { "em_gate_1_gray.active.ypos",                      "7"                             },
+  { "em_gate_1_gray.active.frames",                    "1"                             },
+  { "em_gate_2_gray",                                  "RocksSP.png"                   },
+  { "em_gate_2_gray.xpos",                             "5"                             },
+  { "em_gate_2_gray.ypos",                             "7"                             },
+  { "em_gate_2_gray.frames",                           "1"                             },
+  { "em_gate_2_gray.EDITOR",                           "RocksSP.png"                   },
+  { "em_gate_2_gray.EDITOR.xpos",                      "13"                            },
+  { "em_gate_2_gray.EDITOR.ypos",                      "11"                            },
+  { "em_gate_2_gray.active",                           "RocksSP.png"                   },
+  { "em_gate_2_gray.active.xpos",                      "1"                             },
+  { "em_gate_2_gray.active.ypos",                      "7"                             },
+  { "em_gate_2_gray.active.frames",                    "1"                             },
+  { "em_gate_3_gray",                                  "RocksSP.png"                   },
+  { "em_gate_3_gray.xpos",                             "6"                             },
+  { "em_gate_3_gray.ypos",                             "7"                             },
+  { "em_gate_3_gray.frames",                           "1"                             },
+  { "em_gate_3_gray.EDITOR",                           "RocksSP.png"                   },
+  { "em_gate_3_gray.EDITOR.xpos",                      "14"                            },
+  { "em_gate_3_gray.EDITOR.ypos",                      "11"                            },
+  { "em_gate_3_gray.active",                           "RocksSP.png"                   },
+  { "em_gate_3_gray.active.xpos",                      "2"                             },
+  { "em_gate_3_gray.active.ypos",                      "7"                             },
+  { "em_gate_3_gray.active.frames",                    "1"                             },
+  { "em_gate_4_gray",                                  "RocksSP.png"                   },
+  { "em_gate_4_gray.xpos",                             "7"                             },
+  { "em_gate_4_gray.ypos",                             "7"                             },
+  { "em_gate_4_gray.frames",                           "1"                             },
+  { "em_gate_4_gray.EDITOR",                           "RocksSP.png"                   },
+  { "em_gate_4_gray.EDITOR.xpos",                      "15"                            },
+  { "em_gate_4_gray.EDITOR.ypos",                      "11"                            },
+  { "em_gate_4_gray.active",                           "RocksSP.png"                   },
+  { "em_gate_4_gray.active.xpos",                      "3"                             },
+  { "em_gate_4_gray.active.ypos",                      "7"                             },
+  { "em_gate_4_gray.active.frames",                    "1"                             },
+
+  { "dc_gate_white_gray",                              "RocksSP.png"                   },
+  { "dc_gate_white_gray.xpos",                         "7"                             },
+  { "dc_gate_white_gray.ypos",                         "7"                             },
+  { "dc_gate_white_gray.frames",                       "1"                             },
+  { "dc_gate_white_gray.EDITOR",                       "RocksSP.png"                   },
+  { "dc_gate_white_gray.EDITOR.xpos",                  "15"                            },
+  { "dc_gate_white_gray.EDITOR.ypos",                  "1"                             },
+  { "dc_gate_white_gray.active",                       "RocksSP.png"                   },
+  { "dc_gate_white_gray.active.xpos",                  "14"                            },
+  { "dc_gate_white_gray.active.ypos",                  "1"                             },
+  { "dc_gate_white_gray.active.frames",                        "1"                             },
+
+  { "dc_gate_fake_gray",                               "RocksSP.png"                   },
+  { "dc_gate_fake_gray.xpos",                          "7"                             },
+  { "dc_gate_fake_gray.ypos",                          "7"                             },
+  { "dc_gate_fake_gray.frames",                                "1"                             },
+
+  { "exit_closed",                                     "RocksElements.png"             },
+  { "exit_closed.xpos",                                        "0"                             },
+  { "exit_closed.ypos",                                        "11"                            },
+  { "exit_closed.frames",                              "1"                             },
+  { "exit.opening",                                    "RocksElements.png"             },
+  { "exit.opening.xpos",                               "0"                             },
+  { "exit.opening.ypos",                               "11"                            },
+  { "exit.opening.frames",                             "5"                             },
+  { "exit.opening.delay",                              "6"                             },
+  { "exit.opening.anim_mode",                          "linear"                        },
+  { "exit_open",                                       "RocksElements.png"             },
+  { "exit_open.xpos",                                  "4"                             },
+  { "exit_open.ypos",                                  "11"                            },
+  { "exit_open.frames",                                        "4"                             },
+  { "exit_open.delay",                                 "4"                             },
+  { "exit_open.anim_mode",                             "pingpong"                      },
+  { "exit.closing",                                    "RocksElements.png"             },
+  { "exit.closing.xpos",                               "0"                             },
+  { "exit.closing.ypos",                               "11"                            },
+  { "exit.closing.frames",                             "5"                             },
+  { "exit.closing.delay",                              "6"                             },
+  { "exit.closing.anim_mode",                          "linear,reverse"                },
+
+  { "steel_exit_closed",                               "RocksDC2.png"                  },
+  { "steel_exit_closed.xpos",                          "8"                             },
+  { "steel_exit_closed.ypos",                          "0"                             },
+  { "steel_exit_closed.frames",                                "1"                             },
+  { "steel_exit.opening",                              "RocksDC2.png"                  },
+  { "steel_exit.opening.xpos",                         "8"                             },
+  { "steel_exit.opening.ypos",                         "0"                             },
+  { "steel_exit.opening.frames",                       "5"                             },
+  { "steel_exit.opening.delay",                                "6"                             },
+  { "steel_exit.opening.anim_mode",                    "linear"                        },
+  { "steel_exit_open",                                 "RocksDC2.png"                  },
+  { "steel_exit_open.xpos",                            "12"                            },
+  { "steel_exit_open.ypos",                            "0"                             },
+  { "steel_exit_open.frames",                          "4"                             },
+  { "steel_exit_open.delay",                           "4"                             },
+  { "steel_exit_open.anim_mode",                       "pingpong"                      },
+  { "steel_exit.closing",                              "RocksDC2.png"                  },
+  { "steel_exit.closing.xpos",                         "8"                             },
+  { "steel_exit.closing.ypos",                         "0"                             },
+  { "steel_exit.closing.frames",                       "5"                             },
+  { "steel_exit.closing.delay",                                "6"                             },
+  { "steel_exit.closing.anim_mode",                    "linear,reverse"                },
+
+  { "em_exit_closed",                                  "RocksDC2.png"                  },
+  { "em_exit_closed.xpos",                             "0"                             },
+  { "em_exit_closed.ypos",                             "4"                             },
+  { "em_exit_closed.frames",                           "1"                             },
+  { "em_exit.opening",                                 "RocksDC2.png"                  },
+  { "em_exit.opening.xpos",                            "0"                             },
+  { "em_exit.opening.ypos",                            "4"                             },
+  { "em_exit.opening.frames",                          "5"                             },
+  { "em_exit.opening.delay",                           "6"                             },
+  { "em_exit.opening.anim_mode",                       "linear"                        },
+  { "em_exit_open",                                    "RocksDC2.png"                  },
+  { "em_exit_open.xpos",                               "4"                             },
+  { "em_exit_open.ypos",                               "4"                             },
+  { "em_exit_open.frames",                             "4"                             },
+  { "em_exit_open.delay",                              "4"                             },
+  { "em_exit_open.anim_mode",                          "pingpong"                      },
+  { "em_exit.closing",                                 "RocksDC2.png"                  },
+  { "em_exit.closing.xpos",                            "0"                             },
+  { "em_exit.closing.ypos",                            "6"                             },
+  { "em_exit.closing.frames",                          "5"                             },
+  { "em_exit.closing.delay",                           "6"                             },
+  { "em_exit.closing.anim_mode",                       "linear"                        },
+
+  { "em_steel_exit_closed",                            "RocksDC2.png"                  },
+  { "em_steel_exit_closed.xpos",                       "0"                             },
+  { "em_steel_exit_closed.ypos",                       "5"                             },
+  { "em_steel_exit_closed.frames",                     "1"                             },
+  { "em_steel_exit.opening",                           "RocksDC2.png"                  },
+  { "em_steel_exit.opening.xpos",                      "0"                             },
+  { "em_steel_exit.opening.ypos",                      "5"                             },
+  { "em_steel_exit.opening.frames",                    "5"                             },
+  { "em_steel_exit.opening.delay",                     "6"                             },
+  { "em_steel_exit.opening.anim_mode",                 "linear"                        },
+  { "em_steel_exit_open",                              "RocksDC2.png"                  },
+  { "em_steel_exit_open.xpos",                         "4"                             },
+  { "em_steel_exit_open.ypos",                         "5"                             },
+  { "em_steel_exit_open.frames",                       "4"                             },
+  { "em_steel_exit_open.delay",                                "4"                             },
+  { "em_steel_exit_open.anim_mode",                    "pingpong"                      },
+  { "em_steel_exit.closing",                           "RocksDC2.png"                  },
+  { "em_steel_exit.closing.xpos",                      "0"                             },
+  { "em_steel_exit.closing.ypos",                      "7"                             },
+  { "em_steel_exit.closing.frames",                    "5"                             },
+  { "em_steel_exit.closing.delay",                     "6"                             },
+  { "em_steel_exit.closing.anim_mode",                 "linear"                        },
 
   // images for Emerald Mine Club style elements and actions
 
-  { "balloon",                                 "RocksDC.png"           },
-  { "balloon.xpos",                            "12"                    },
-  { "balloon.ypos",                            "7"                     },
-  { "balloon.frames",                          "1"                     },
-  { "balloon.moving",                          "RocksDC.png"           },
-  { "balloon.moving.xpos",                     "12"                    },
-  { "balloon.moving.ypos",                     "7"                     },
-  { "balloon.moving.frames",                   "4"                     },
-  { "balloon.moving.anim_mode",                        "pingpong"              },
-  { "balloon.moving.delay",                    "2"                     },
-  { "balloon.pushing",                         "RocksDC.png"           },
-  { "balloon.pushing.xpos",                    "12"                    },
-  { "balloon.pushing.ypos",                    "7"                     },
-  { "balloon.pushing.frames",                  "4"                     },
-  { "balloon.pushing.anim_mode",               "pingpong"              },
-  { "balloon.pushing.delay",                   "2"                     },
-  { "balloon_switch_left",                     "RocksDC.png"           },
-  { "balloon_switch_left.xpos",                        "8"                     },
-  { "balloon_switch_left.ypos",                        "7"                     },
-  { "balloon_switch_left.frames",              "1"                     },
-  { "balloon_switch_right",                    "RocksDC.png"           },
-  { "balloon_switch_right.xpos",               "9"                     },
-  { "balloon_switch_right.ypos",               "7"                     },
-  { "balloon_switch_right.frames",             "1"                     },
-  { "balloon_switch_up",                       "RocksDC.png"           },
-  { "balloon_switch_up.xpos",                  "10"                    },
-  { "balloon_switch_up.ypos",                  "7"                     },
-  { "balloon_switch_up.frames",                        "1"                     },
-  { "balloon_switch_down",                     "RocksDC.png"           },
-  { "balloon_switch_down.xpos",                        "11"                    },
-  { "balloon_switch_down.ypos",                        "7"                     },
-  { "balloon_switch_down.frames",              "1"                     },
-  { "balloon_switch_any",                      "RocksDC.png"           },
-  { "balloon_switch_any.xpos",                 "15"                    },
-  { "balloon_switch_any.ypos",                 "0"                     },
-  { "balloon_switch_any.frames",               "1"                     },
-  { "balloon_switch_none",                     "RocksDC.png"           },
-  { "balloon_switch_none.xpos",                        "13"                    },
-  { "balloon_switch_none.ypos",                        "5"                     },
-  { "balloon_switch_none.frames",              "1"                     },
-
-  { "spring",                                  "RocksDC.png"           },
-  { "spring.xpos",                             "8"                     },
-  { "spring.ypos",                             "13"                    },
-  { "spring.frames",                           "1"                     },
-
-  { "spring.left",                             UNDEFINED_FILENAME      },
-  { "spring.left.clone_from",                  "spring"                },
-  { "spring.right",                            UNDEFINED_FILENAME      },
-  { "spring.right.clone_from",                 "spring"                },
-
-  { "emc_steelwall_1",                         "RocksDC.png"           },
-  { "emc_steelwall_1.xpos",                    "14"                    },
-  { "emc_steelwall_1.ypos",                    "0"                     },
-  { "emc_steelwall_1.frames",                  "1"                     },
-  { "emc_steelwall_2",                         "RocksEMC.png"          },
-  { "emc_steelwall_2.xpos",                    "9"                     },
-  { "emc_steelwall_2.ypos",                    "8"                     },
-  { "emc_steelwall_2.frames",                  "1"                     },
-  { "emc_steelwall_3",                         "RocksEMC.png"          },
-  { "emc_steelwall_3.xpos",                    "9"                     },
-  { "emc_steelwall_3.ypos",                    "9"                     },
-  { "emc_steelwall_3.frames",                  "1"                     },
-  { "emc_steelwall_4",                         "RocksEMC.png"          },
-  { "emc_steelwall_4.xpos",                    "9"                     },
-  { "emc_steelwall_4.ypos",                    "10"                    },
-  { "emc_steelwall_4.frames",                  "1"                     },
-
-  { "emc_wall_1",                              "RocksDC.png"           },
-  { "emc_wall_1.xpos",                         "13"                    },
-  { "emc_wall_1.ypos",                         "6"                     },
-  { "emc_wall_1.frames",                       "1"                     },
-  { "emc_wall_2",                              "RocksDC.png"           },
-  { "emc_wall_2.xpos",                         "14"                    },
-  { "emc_wall_2.ypos",                         "6"                     },
-  { "emc_wall_2.frames",                       "1"                     },
-  { "emc_wall_3",                              "RocksDC.png"           },
-  { "emc_wall_3.xpos",                         "15"                    },
-  { "emc_wall_3.ypos",                         "6"                     },
-  { "emc_wall_3.frames",                       "1"                     },
-  { "emc_wall_4",                              "RocksDC.png"           },
-  { "emc_wall_4.xpos",                         "14"                    },
-  { "emc_wall_4.ypos",                         "1"                     },
-  { "emc_wall_4.frames",                       "1"                     },
-  { "emc_wall_5",                              "RocksDC.png"           },
-  { "emc_wall_5.xpos",                         "15"                    },
-  { "emc_wall_5.ypos",                         "1"                     },
-  { "emc_wall_5.frames",                       "1"                     },
-  { "emc_wall_6",                              "RocksDC.png"           },
-  { "emc_wall_6.xpos",                         "14"                    },
-  { "emc_wall_6.ypos",                         "2"                     },
-  { "emc_wall_6.frames",                       "1"                     },
-  { "emc_wall_7",                              "RocksDC.png"           },
-  { "emc_wall_7.xpos",                         "15"                    },
-  { "emc_wall_7.ypos",                         "2"                     },
-  { "emc_wall_7.frames",                       "1"                     },
-  { "emc_wall_8",                              "RocksEMC.png"          },
-  { "emc_wall_8.xpos",                         "8"                     },
-  { "emc_wall_8.ypos",                         "7"                     },
-  { "emc_wall_8.frames",                       "1"                     },
+  { "balloon",                                         "RocksDC.png"                   },
+  { "balloon.xpos",                                    "12"                            },
+  { "balloon.ypos",                                    "7"                             },
+  { "balloon.frames",                                  "1"                             },
+  { "balloon.moving",                                  "RocksDC.png"                   },
+  { "balloon.moving.xpos",                             "12"                            },
+  { "balloon.moving.ypos",                             "7"                             },
+  { "balloon.moving.frames",                           "4"                             },
+  { "balloon.moving.anim_mode",                                "pingpong"                      },
+  { "balloon.moving.delay",                            "2"                             },
+  { "balloon.pushing",                                 "RocksDC.png"                   },
+  { "balloon.pushing.xpos",                            "12"                            },
+  { "balloon.pushing.ypos",                            "7"                             },
+  { "balloon.pushing.frames",                          "4"                             },
+  { "balloon.pushing.anim_mode",                       "pingpong"                      },
+  { "balloon.pushing.delay",                           "2"                             },
+  { "balloon_switch_left",                             "RocksDC.png"                   },
+  { "balloon_switch_left.xpos",                                "8"                             },
+  { "balloon_switch_left.ypos",                                "7"                             },
+  { "balloon_switch_left.frames",                      "1"                             },
+  { "balloon_switch_right",                            "RocksDC.png"                   },
+  { "balloon_switch_right.xpos",                       "9"                             },
+  { "balloon_switch_right.ypos",                       "7"                             },
+  { "balloon_switch_right.frames",                     "1"                             },
+  { "balloon_switch_up",                               "RocksDC.png"                   },
+  { "balloon_switch_up.xpos",                          "10"                            },
+  { "balloon_switch_up.ypos",                          "7"                             },
+  { "balloon_switch_up.frames",                                "1"                             },
+  { "balloon_switch_down",                             "RocksDC.png"                   },
+  { "balloon_switch_down.xpos",                                "11"                            },
+  { "balloon_switch_down.ypos",                                "7"                             },
+  { "balloon_switch_down.frames",                      "1"                             },
+  { "balloon_switch_any",                              "RocksDC.png"                   },
+  { "balloon_switch_any.xpos",                         "15"                            },
+  { "balloon_switch_any.ypos",                         "0"                             },
+  { "balloon_switch_any.frames",                       "1"                             },
+  { "balloon_switch_none",                             "RocksDC.png"                   },
+  { "balloon_switch_none.xpos",                                "13"                            },
+  { "balloon_switch_none.ypos",                                "5"                             },
+  { "balloon_switch_none.frames",                      "1"                             },
+
+  { "spring",                                          "RocksDC.png"                   },
+  { "spring.xpos",                                     "8"                             },
+  { "spring.ypos",                                     "13"                            },
+  { "spring.frames",                                   "1"                             },
+
+  { "spring.left",                                     UNDEFINED_FILENAME              },
+  { "spring.left.clone_from",                          "spring"                        },
+  { "spring.right",                                    UNDEFINED_FILENAME              },
+  { "spring.right.clone_from",                         "spring"                        },
+
+  { "emc_steelwall_1",                                 "RocksDC.png"                   },
+  { "emc_steelwall_1.xpos",                            "14"                            },
+  { "emc_steelwall_1.ypos",                            "0"                             },
+  { "emc_steelwall_1.frames",                          "1"                             },
+  { "emc_steelwall_2",                                 "RocksEMC.png"                  },
+  { "emc_steelwall_2.xpos",                            "9"                             },
+  { "emc_steelwall_2.ypos",                            "8"                             },
+  { "emc_steelwall_2.frames",                          "1"                             },
+  { "emc_steelwall_3",                                 "RocksEMC.png"                  },
+  { "emc_steelwall_3.xpos",                            "9"                             },
+  { "emc_steelwall_3.ypos",                            "9"                             },
+  { "emc_steelwall_3.frames",                          "1"                             },
+  { "emc_steelwall_4",                                 "RocksEMC.png"                  },
+  { "emc_steelwall_4.xpos",                            "9"                             },
+  { "emc_steelwall_4.ypos",                            "10"                            },
+  { "emc_steelwall_4.frames",                          "1"                             },
+
+  { "emc_wall_1",                                      "RocksDC.png"                   },
+  { "emc_wall_1.xpos",                                 "13"                            },
+  { "emc_wall_1.ypos",                                 "6"                             },
+  { "emc_wall_1.frames",                               "1"                             },
+  { "emc_wall_2",                                      "RocksDC.png"                   },
+  { "emc_wall_2.xpos",                                 "14"                            },
+  { "emc_wall_2.ypos",                                 "6"                             },
+  { "emc_wall_2.frames",                               "1"                             },
+  { "emc_wall_3",                                      "RocksDC.png"                   },
+  { "emc_wall_3.xpos",                                 "15"                            },
+  { "emc_wall_3.ypos",                                 "6"                             },
+  { "emc_wall_3.frames",                               "1"                             },
+  { "emc_wall_4",                                      "RocksDC.png"                   },
+  { "emc_wall_4.xpos",                                 "14"                            },
+  { "emc_wall_4.ypos",                                 "1"                             },
+  { "emc_wall_4.frames",                               "1"                             },
+  { "emc_wall_5",                                      "RocksDC.png"                   },
+  { "emc_wall_5.xpos",                                 "15"                            },
+  { "emc_wall_5.ypos",                                 "1"                             },
+  { "emc_wall_5.frames",                               "1"                             },
+  { "emc_wall_6",                                      "RocksDC.png"                   },
+  { "emc_wall_6.xpos",                                 "14"                            },
+  { "emc_wall_6.ypos",                                 "2"                             },
+  { "emc_wall_6.frames",                               "1"                             },
+  { "emc_wall_7",                                      "RocksDC.png"                   },
+  { "emc_wall_7.xpos",                                 "15"                            },
+  { "emc_wall_7.ypos",                                 "2"                             },
+  { "emc_wall_7.frames",                               "1"                             },
+  { "emc_wall_8",                                      "RocksEMC.png"                  },
+  { "emc_wall_8.xpos",                                 "8"                             },
+  { "emc_wall_8.ypos",                                 "7"                             },
+  { "emc_wall_8.frames",                               "1"                             },
 
   // images for Diamond Caves style elements and actions
 
-  { "invisible_steelwall",                     "RocksSP.png"           },
-  { "invisible_steelwall.xpos",                        "3"                     },
-  { "invisible_steelwall.ypos",                        "5"                     },
-  { "invisible_steelwall.frames",              "1"                     },
-  { "invisible_steelwall.EDITOR",              "RocksSP.png"           },
-  { "invisible_steelwall.EDITOR.xpos",         "1"                     },
-  { "invisible_steelwall.EDITOR.ypos",         "5"                     },
-  { "invisible_steelwall.active",              "RocksSP.png"           },
-  { "invisible_steelwall.active.xpos",         "1"                     },
-  { "invisible_steelwall.active.ypos",         "5"                     },
-  { "invisible_steelwall.active.frames",       "1"                     },
-
-  { "invisible_wall",                          "RocksSP.png"           },
-  { "invisible_wall.xpos",                     "7"                     },
-  { "invisible_wall.ypos",                     "5"                     },
-  { "invisible_wall.frames",                   "1"                     },
-  { "invisible_wall.EDITOR",                   "RocksSP.png"           },
-  { "invisible_wall.EDITOR.xpos",              "5"                     },
-  { "invisible_wall.EDITOR.ypos",              "5"                     },
-  { "invisible_wall.active",                   "RocksSP.png"           },
-  { "invisible_wall.active.xpos",              "5"                     },
-  { "invisible_wall.active.ypos",              "5"                     },
-  { "invisible_wall.active.frames",            "1"                     },
-
-  { "invisible_sand",                          "RocksSP.png"           },
-  { "invisible_sand.xpos",                     "0"                     },
-  { "invisible_sand.ypos",                     "0"                     },
-  { "invisible_sand.frames",                   "1"                     },
-  { "invisible_sand.EDITOR",                   "RocksEMC.png"          },
-  { "invisible_sand.EDITOR.xpos",              "2"                     },
-  { "invisible_sand.EDITOR.ypos",              "4"                     },
-  { "invisible_sand.active",                   "RocksEMC.png"          },
-  { "invisible_sand.active.xpos",              "2"                     },
-  { "invisible_sand.active.ypos",              "4"                     },
-  { "invisible_sand.active.frames",            "1"                     },
-  { "invisible_sand.active.CRUMBLED",          "RocksEMC.png"          },
-  { "invisible_sand.active.CRUMBLED.xpos",     "3"                     },
-  { "invisible_sand.active.CRUMBLED.ypos",     "4"                     },
-  { "invisible_sand.active.CRUMBLED.frames",   "1"                     },
-  { "invisible_sand.active.digging.left",      "RocksEMC.png"          },
-  { "invisible_sand.active.digging.left.xpos", "6"                     },
-  { "invisible_sand.active.digging.left.ypos", "2"                     },
-  { "invisible_sand.active.digging.left.frames","3"                    },
-  { "invisible_sand.active.digging.left.delay",        "2"                     },
-  { "invisible_sand.active.digging.left.anim_mode","linear"            },
-  { "invisible_sand.active.digging.right",     "RocksEMC.png"          },
-  { "invisible_sand.active.digging.right.xpos",        "9"                     },
-  { "invisible_sand.active.digging.right.ypos",        "2"                     },
-  { "invisible_sand.active.digging.right.frames","3"                   },
-  { "invisible_sand.active.digging.right.delay","2"                    },
-  { "invisible_sand.active.digging.right.anim_mode","linear"           },
-  { "invisible_sand.active.digging.up",                "RocksEMC.png"          },
-  { "invisible_sand.active.digging.up.xpos",   "0"                     },
-  { "invisible_sand.active.digging.up.ypos",   "2"                     },
-  { "invisible_sand.active.digging.up.frames", "3"                     },
-  { "invisible_sand.active.digging.up.delay",  "2"                     },
-  { "invisible_sand.active.digging.up.anim_mode","linear"              },
-  { "invisible_sand.active.digging.down",      "RocksEMC.png"          },
-  { "invisible_sand.active.digging.down.xpos", "3"                     },
-  { "invisible_sand.active.digging.down.ypos", "2"                     },
-  { "invisible_sand.active.digging.down.frames","3"                    },
-  { "invisible_sand.active.digging.down.delay",        "2"                     },
-  { "invisible_sand.active.digging.down.anim_mode","linear"            },
-  { "invisible_sand.active.digging.left.CRUMBLED",     "RocksEMC.png"  },
-  { "invisible_sand.active.digging.left.CRUMBLED.xpos",        "6"             },
-  { "invisible_sand.active.digging.left.CRUMBLED.ypos",        "3"             },
-  { "invisible_sand.active.digging.left.CRUMBLED.frames","3"           },
-  { "invisible_sand.active.digging.left.CRUMBLED.delay","2"            },
-  { "invisible_sand.active.digging.left.CRUMBLED.anim_mode","linear"   },
-  { "invisible_sand.active.digging.right.CRUMBLED",    "RocksEMC.png"  },
-  { "invisible_sand.active.digging.right.CRUMBLED.xpos","9"            },
-  { "invisible_sand.active.digging.right.CRUMBLED.ypos","3"            },
-  { "invisible_sand.active.digging.right.CRUMBLED.frames","3"          },
-  { "invisible_sand.active.digging.right.CRUMBLED.delay","2"           },
-  { "invisible_sand.active.digging.right.CRUMBLED.anim_mode","linear"  },
-  { "invisible_sand.active.digging.up.CRUMBLED",       "RocksEMC.png"  },
-  { "invisible_sand.active.digging.up.CRUMBLED.xpos",  "0"             },
-  { "invisible_sand.active.digging.up.CRUMBLED.ypos",  "3"             },
-  { "invisible_sand.active.digging.up.CRUMBLED.frames",        "3"             },
-  { "invisible_sand.active.digging.up.CRUMBLED.delay", "2"             },
-  { "invisible_sand.active.digging.up.CRUMBLED.anim_mode","linear"     },
-  { "invisible_sand.active.digging.down.CRUMBLED",     "RocksEMC.png"  },
-  { "invisible_sand.active.digging.down.CRUMBLED.xpos",        "3"             },
-  { "invisible_sand.active.digging.down.CRUMBLED.ypos",        "3"             },
-  { "invisible_sand.active.digging.down.CRUMBLED.frames","3"           },
-  { "invisible_sand.active.digging.down.CRUMBLED.delay","2"            },
-  { "invisible_sand.active.digging.down.CRUMBLED.anim_mode","linear"   },
-
-  { "conveyor_belt_1_middle",                  "RocksDC.png"           },
-  { "conveyor_belt_1_middle.xpos",             "0"                     },
-  { "conveyor_belt_1_middle.ypos",             "0"                     },
-  { "conveyor_belt_1_middle.frames",           "1"                     },
-  { "conveyor_belt_1_middle.active",           "RocksDC.png"           },
-  { "conveyor_belt_1_middle.active.xpos",      "0"                     },
-  { "conveyor_belt_1_middle.active.ypos",      "0"                     },
-  { "conveyor_belt_1_middle.active.frames",    "8"                     },
-  { "conveyor_belt_1_middle.active.delay",     "2"                     },
-  { "conveyor_belt_1_left",                    "RocksDC.png"           },
-  { "conveyor_belt_1_left.xpos",               "0"                     },
-  { "conveyor_belt_1_left.ypos",               "1"                     },
-  { "conveyor_belt_1_left.frames",             "1"                     },
-  { "conveyor_belt_1_left.active",             "RocksDC.png"           },
-  { "conveyor_belt_1_left.active.xpos",                "0"                     },
-  { "conveyor_belt_1_left.active.ypos",                "1"                     },
-  { "conveyor_belt_1_left.active.frames",      "8"                     },
-  { "conveyor_belt_1_left.active.delay",       "2"                     },
-  { "conveyor_belt_1_right",                   "RocksDC.png"           },
-  { "conveyor_belt_1_right.xpos",              "0"                     },
-  { "conveyor_belt_1_right.ypos",              "2"                     },
-  { "conveyor_belt_1_right.frames",            "1"                     },
-  { "conveyor_belt_1_right.active",            "RocksDC.png"           },
-  { "conveyor_belt_1_right.active.xpos",       "0"                     },
-  { "conveyor_belt_1_right.active.ypos",       "2"                     },
-  { "conveyor_belt_1_right.active.frames",     "8"                     },
-  { "conveyor_belt_1_right.active.delay",      "2"                     },
-  { "conveyor_belt_1_switch_left",             "RocksDC.png"           },
-  { "conveyor_belt_1_switch_left.xpos",                "0"                     },
-  { "conveyor_belt_1_switch_left.ypos",                "12"                    },
-  { "conveyor_belt_1_switch_left.frames",      "1"                     },
-  { "conveyor_belt_1_switch_middle",           "RocksDC.png"           },
-  { "conveyor_belt_1_switch_middle.xpos",      "0"                     },
-  { "conveyor_belt_1_switch_middle.ypos",      "13"                    },
-  { "conveyor_belt_1_switch_middle.frames",    "1"                     },
-  { "conveyor_belt_1_switch_right",            "RocksDC.png"           },
-  { "conveyor_belt_1_switch_right.xpos",       "0"                     },
-  { "conveyor_belt_1_switch_right.ypos",       "14"                    },
-  { "conveyor_belt_1_switch_right.frames",     "1"                     },
-
-  { "conveyor_belt_2_middle",                  "RocksDC.png"           },
-  { "conveyor_belt_2_middle.xpos",             "0"                     },
-  { "conveyor_belt_2_middle.ypos",             "3"                     },
-  { "conveyor_belt_2_middle.frames",           "1"                     },
-  { "conveyor_belt_2_middle.active",           "RocksDC.png"           },
-  { "conveyor_belt_2_middle.active.xpos",      "0"                     },
-  { "conveyor_belt_2_middle.active.ypos",      "3"                     },
-  { "conveyor_belt_2_middle.active.frames",    "8"                     },
-  { "conveyor_belt_2_middle.active.delay",     "2"                     },
-  { "conveyor_belt_2_left",                    "RocksDC.png"           },
-  { "conveyor_belt_2_left.xpos",               "0"                     },
-  { "conveyor_belt_2_left.ypos",               "4"                     },
-  { "conveyor_belt_2_left.frames",             "1"                     },
-  { "conveyor_belt_2_left.active",             "RocksDC.png"           },
-  { "conveyor_belt_2_left.active.xpos",                "0"                     },
-  { "conveyor_belt_2_left.active.ypos",                "4"                     },
-  { "conveyor_belt_2_left.active.frames",      "8"                     },
-  { "conveyor_belt_2_left.active.delay",       "2"                     },
-  { "conveyor_belt_2_right",                   "RocksDC.png"           },
-  { "conveyor_belt_2_right.xpos",              "0"                     },
-  { "conveyor_belt_2_right.ypos",              "5"                     },
-  { "conveyor_belt_2_right.frames",            "1"                     },
-  { "conveyor_belt_2_right.active",            "RocksDC.png"           },
-  { "conveyor_belt_2_right.active.xpos",       "0"                     },
-  { "conveyor_belt_2_right.active.ypos",       "5"                     },
-  { "conveyor_belt_2_right.active.frames",     "8"                     },
-  { "conveyor_belt_2_right.active.delay",      "2"                     },
-  { "conveyor_belt_2_switch_left",             "RocksDC.png"           },
-  { "conveyor_belt_2_switch_left.xpos",                "1"                     },
-  { "conveyor_belt_2_switch_left.ypos",                "12"                    },
-  { "conveyor_belt_2_switch_left.frames",      "1"                     },
-  { "conveyor_belt_2_switch_middle",           "RocksDC.png"           },
-  { "conveyor_belt_2_switch_middle.xpos",      "1"                     },
-  { "conveyor_belt_2_switch_middle.ypos",      "13"                    },
-  { "conveyor_belt_2_switch_middle.frames",    "1"                     },
-  { "conveyor_belt_2_switch_right",            "RocksDC.png"           },
-  { "conveyor_belt_2_switch_right.xpos",       "1"                     },
-  { "conveyor_belt_2_switch_right.ypos",       "14"                    },
-  { "conveyor_belt_2_switch_right.frames",     "1"                     },
-
-  { "conveyor_belt_3_middle",                  "RocksDC.png"           },
-  { "conveyor_belt_3_middle.xpos",             "0"                     },
-  { "conveyor_belt_3_middle.ypos",             "6"                     },
-  { "conveyor_belt_3_middle.frames",           "1"                     },
-  { "conveyor_belt_3_middle.active",           "RocksDC.png"           },
-  { "conveyor_belt_3_middle.active.xpos",      "0"                     },
-  { "conveyor_belt_3_middle.active.ypos",      "6"                     },
-  { "conveyor_belt_3_middle.active.frames",    "8"                     },
-  { "conveyor_belt_3_middle.active.delay",     "2"                     },
-  { "conveyor_belt_3_left",                    "RocksDC.png"           },
-  { "conveyor_belt_3_left.xpos",               "0"                     },
-  { "conveyor_belt_3_left.ypos",               "7"                     },
-  { "conveyor_belt_3_left.frames",             "1"                     },
-  { "conveyor_belt_3_left.active",             "RocksDC.png"           },
-  { "conveyor_belt_3_left.active.xpos",                "0"                     },
-  { "conveyor_belt_3_left.active.ypos",                "7"                     },
-  { "conveyor_belt_3_left.active.frames",      "8"                     },
-  { "conveyor_belt_3_left.active.delay",       "2"                     },
-  { "conveyor_belt_3_right",                   "RocksDC.png"           },
-  { "conveyor_belt_3_right.xpos",              "0"                     },
-  { "conveyor_belt_3_right.ypos",              "8"                     },
-  { "conveyor_belt_3_right.frames",            "1"                     },
-  { "conveyor_belt_3_right.active",            "RocksDC.png"           },
-  { "conveyor_belt_3_right.active.xpos",       "0"                     },
-  { "conveyor_belt_3_right.active.ypos",       "8"                     },
-  { "conveyor_belt_3_right.active.frames",     "8"                     },
-  { "conveyor_belt_3_right.active.delay",      "2"                     },
-  { "conveyor_belt_3_switch_left",             "RocksDC.png"           },
-  { "conveyor_belt_3_switch_left.xpos",                "2"                     },
-  { "conveyor_belt_3_switch_left.ypos",                "12"                    },
-  { "conveyor_belt_3_switch_left.frames",      "1"                     },
-  { "conveyor_belt_3_switch_middle",           "RocksDC.png"           },
-  { "conveyor_belt_3_switch_middle.xpos",      "2"                     },
-  { "conveyor_belt_3_switch_middle.ypos",      "13"                    },
-  { "conveyor_belt_3_switch_middle.frames",    "1"                     },
-  { "conveyor_belt_3_switch_right",            "RocksDC.png"           },
-  { "conveyor_belt_3_switch_right.xpos",       "2"                     },
-  { "conveyor_belt_3_switch_right.ypos",       "14"                    },
-  { "conveyor_belt_3_switch_right.frames",     "1"                     },
-
-  { "conveyor_belt_4_middle",                  "RocksDC.png"           },
-  { "conveyor_belt_4_middle.xpos",             "0"                     },
-  { "conveyor_belt_4_middle.ypos",             "9"                     },
-  { "conveyor_belt_4_middle.frames",           "1"                     },
-  { "conveyor_belt_4_middle.active",           "RocksDC.png"           },
-  { "conveyor_belt_4_middle.active.xpos",      "0"                     },
-  { "conveyor_belt_4_middle.active.ypos",      "9"                     },
-  { "conveyor_belt_4_middle.active.frames",    "8"                     },
-  { "conveyor_belt_4_middle.active.delay",     "2"                     },
-  { "conveyor_belt_4_left",                    "RocksDC.png"           },
-  { "conveyor_belt_4_left.xpos",               "0"                     },
-  { "conveyor_belt_4_left.ypos",               "10"                    },
-  { "conveyor_belt_4_left.frames",             "1"                     },
-  { "conveyor_belt_4_left.active",             "RocksDC.png"           },
-  { "conveyor_belt_4_left.active.xpos",                "0"                     },
-  { "conveyor_belt_4_left.active.ypos",                "10"                    },
-  { "conveyor_belt_4_left.active.frames",      "8"                     },
-  { "conveyor_belt_4_left.active.delay",       "2"                     },
-  { "conveyor_belt_4_right",                   "RocksDC.png"           },
-  { "conveyor_belt_4_right.xpos",              "0"                     },
-  { "conveyor_belt_4_right.ypos",              "11"                    },
-  { "conveyor_belt_4_right.frames",            "1"                     },
-  { "conveyor_belt_4_right.active",            "RocksDC.png"           },
-  { "conveyor_belt_4_right.active.xpos",       "0"                     },
-  { "conveyor_belt_4_right.active.ypos",       "11"                    },
-  { "conveyor_belt_4_right.active.frames",     "8"                     },
-  { "conveyor_belt_4_right.active.delay",      "2"                     },
-  { "conveyor_belt_4_switch_left",             "RocksDC.png"           },
-  { "conveyor_belt_4_switch_left.xpos",                "3"                     },
-  { "conveyor_belt_4_switch_left.ypos",                "12"                    },
-  { "conveyor_belt_4_switch_left.frames",      "1"                     },
-  { "conveyor_belt_4_switch_middle",           "RocksDC.png"           },
-  { "conveyor_belt_4_switch_middle.xpos",      "3"                     },
-  { "conveyor_belt_4_switch_middle.ypos",      "13"                    },
-  { "conveyor_belt_4_switch_middle.frames",    "1"                     },
-  { "conveyor_belt_4_switch_right",            "RocksDC.png"           },
-  { "conveyor_belt_4_switch_right.xpos",       "3"                     },
-  { "conveyor_belt_4_switch_right.ypos",       "14"                    },
-  { "conveyor_belt_4_switch_right.frames",     "1"                     },
-
-  { "switchgate_switch_up",                    "RocksDC.png"           },
-  { "switchgate_switch_up.xpos",               "4"                     },
-  { "switchgate_switch_up.ypos",               "12"                    },
-  { "switchgate_switch_up.frames",             "1"                     },
-  { "switchgate_switch_down",                  "RocksDC.png"           },
-  { "switchgate_switch_down.xpos",             "5"                     },
-  { "switchgate_switch_down.ypos",             "12"                    },
-  { "switchgate_switch_down.frames",           "1"                     },
-
-  { "dc_switchgate_switch_up",                 "RocksDC2.png"          },
-  { "dc_switchgate_switch_up.xpos",            "10"                    },
-  { "dc_switchgate_switch_up.ypos",            "1"                     },
-  { "dc_switchgate_switch_up.frames",          "1"                     },
-  { "dc_switchgate_switch_down",               "RocksDC2.png"          },
-  { "dc_switchgate_switch_down.xpos",          "11"                    },
-  { "dc_switchgate_switch_down.ypos",          "1"                     },
-  { "dc_switchgate_switch_down.frames",                "1"                     },
-
-  { "light_switch",                            "RocksDC.png"           },
-  { "light_switch.xpos",                       "6"                     },
-  { "light_switch.ypos",                       "12"                    },
-  { "light_switch.frames",                     "1"                     },
-  { "light_switch.active",                     "RocksDC.png"           },
-  { "light_switch.active.xpos",                        "7"                     },
-  { "light_switch.active.ypos",                        "12"                    },
-  { "light_switch.active.frames",              "1"                     },
-
-  { "timegate_switch",                         "RocksDC.png"           },
-  { "timegate_switch.xpos",                    "0"                     },
-  { "timegate_switch.ypos",                    "15"                    },
-  { "timegate_switch.frames",                  "1"                     },
-  { "timegate_switch.active",                  "RocksDC.png"           },
-  { "timegate_switch.active.xpos",             "0"                     },
-  { "timegate_switch.active.ypos",             "15"                    },
-  { "timegate_switch.active.frames",           "4"                     },
-
-  { "dc_timegate_switch",                      "RocksDC2.png"          },
-  { "dc_timegate_switch.xpos",                 "12"                    },
-  { "dc_timegate_switch.ypos",                 "1"                     },
-  { "dc_timegate_switch.frames",               "1"                     },
-  { "dc_timegate_switch.active",               "RocksDC2.png"          },
-  { "dc_timegate_switch.active.xpos",          "12"                    },
-  { "dc_timegate_switch.active.ypos",          "1"                     },
-  { "dc_timegate_switch.active.frames",                "4"                     },
-
-  { "envelope_1",                              "RocksMore.png"         },
-  { "envelope_1.xpos",                         "0"                     },
-  { "envelope_1.ypos",                         "4"                     },
-  { "envelope_1.frames",                       "1"                     },
-  { "envelope_1.collecting",                   "RocksCollect.png"      },
-  { "envelope_1.collecting.xpos",              "7"                     },
-  { "envelope_1.collecting.ypos",              "8"                     },
-  { "envelope_1.collecting.frames",            "7"                     },
-  { "envelope_1.collecting.anim_mode",         "linear"                },
-  { "envelope_2",                              "RocksMore.png"         },
-  { "envelope_2.xpos",                         "1"                     },
-  { "envelope_2.ypos",                         "4"                     },
-  { "envelope_2.frames",                       "1"                     },
-  { "envelope_2.collecting",                   "RocksCollect.png"      },
-  { "envelope_2.collecting.xpos",              "7"                     },
-  { "envelope_2.collecting.ypos",              "9"                     },
-  { "envelope_2.collecting.frames",            "7"                     },
-  { "envelope_2.collecting.anim_mode",         "linear"                },
-  { "envelope_3",                              "RocksMore.png"         },
-  { "envelope_3.xpos",                         "2"                     },
-  { "envelope_3.ypos",                         "4"                     },
-  { "envelope_3.frames",                       "1"                     },
-  { "envelope_3.collecting",                   "RocksCollect.png"      },
-  { "envelope_3.collecting.xpos",              "7"                     },
-  { "envelope_3.collecting.ypos",              "10"                    },
-  { "envelope_3.collecting.frames",            "7"                     },
-  { "envelope_3.collecting.anim_mode",         "linear"                },
-  { "envelope_4",                              "RocksMore.png"         },
-  { "envelope_4.xpos",                         "3"                     },
-  { "envelope_4.ypos",                         "4"                     },
-  { "envelope_4.frames",                       "1"                     },
-  { "envelope_4.collecting",                   "RocksCollect.png"      },
-  { "envelope_4.collecting.xpos",              "7"                     },
-  { "envelope_4.collecting.ypos",              "11"                    },
-  { "envelope_4.collecting.frames",            "7"                     },
-  { "envelope_4.collecting.anim_mode",         "linear"                },
-
-  { "sign_radioactivity",                      "RocksDC.png"           },
-  { "sign_radioactivity.xpos",                 "4"                     },
-  { "sign_radioactivity.ypos",                 "13"                    },
-  { "sign_radioactivity.frames",               "1"                     },
-
-  { "sign_give_way",                           "RocksDC.png"           },
-  { "sign_give_way.xpos",                      "5"                     },
-  { "sign_give_way.ypos",                      "13"                    },
-  { "sign_give_way.frames",                    "1"                     },
-
-  { "sign_no_entry",                           "RocksDC.png"           },
-  { "sign_no_entry.xpos",                      "6"                     },
-  { "sign_no_entry.ypos",                      "13"                    },
-  { "sign_no_entry.frames",                    "1"                     },
-
-  { "sign_emergency_exit",                     "RocksDC.png"           },
-  { "sign_emergency_exit.xpos",                        "7"                     },
-  { "sign_emergency_exit.ypos",                        "13"                    },
-  { "sign_emergency_exit.frames",              "1"                     },
-
-  { "sign_yin_yang",                           "RocksDC.png"           },
-  { "sign_yin_yang.xpos",                      "4"                     },
-  { "sign_yin_yang.ypos",                      "14"                    },
-  { "sign_yin_yang.frames",                    "1"                     },
-
-  { "sign_exclamation",                                "RocksDC.png"           },
-  { "sign_exclamation.xpos",                   "5"                     },
-  { "sign_exclamation.ypos",                   "14"                    },
-  { "sign_exclamation.frames",                 "1"                     },
-
-  { "sign_stop",                               "RocksDC.png"           },
-  { "sign_stop.xpos",                          "6"                     },
-  { "sign_stop.ypos",                          "14"                    },
-  { "sign_stop.frames",                                "1"                     },
-
-  { "sign_parking",                            "RocksDC.png"           },
-  { "sign_parking.xpos",                       "6"                     },
-  { "sign_parking.ypos",                       "15"                    },
-  { "sign_parking.frames",                     "1"                     },
-
-  { "sign_wheelchair",                         "RocksDC.png"           },
-  { "sign_wheelchair.xpos",                    "7"                     },
-  { "sign_wheelchair.ypos",                    "15"                    },
-  { "sign_wheelchair.frames",                  "1"                     },
-
-  { "sign_entry_forbidden",                    "RocksDC.png"           },
-  { "sign_entry_forbidden.xpos",               "12"                    },
-  { "sign_entry_forbidden.ypos",               "15"                    },
-  { "sign_entry_forbidden.frames",             "1"                     },
-
-  { "sperms",                                  "RocksDC2.png"          },
-  { "sperms.xpos",                             "11"                    },
-  { "sperms.ypos",                             "3"                     },
-  { "sperms.frames",                           "1"                     },
-
-  { "bullet",                                  "RocksDC2.png"          },
-  { "bullet.xpos",                             "12"                    },
-  { "bullet.ypos",                             "3"                     },
-  { "bullet.frames",                           "1"                     },
-
-  { "heart",                                   "RocksDC2.png"          },
-  { "heart.xpos",                              "13"                    },
-  { "heart.ypos",                              "3"                     },
-  { "heart.frames",                            "1"                     },
-
-  { "cross",                                   "RocksDC2.png"          },
-  { "cross.xpos",                              "14"                    },
-  { "cross.ypos",                              "3"                     },
-  { "cross.frames",                            "1"                     },
-
-  { "frankie",                                 "RocksDC2.png"          },
-  { "frankie.xpos",                            "15"                    },
-  { "frankie.ypos",                            "3"                     },
-  { "frankie.frames",                          "1"                     },
-
-  { "sign_sperms",                             "RocksDC2.png"          },
-  { "sign_sperms.xpos",                                "11"                    },
-  { "sign_sperms.ypos",                                "2"                     },
-  { "sign_sperms.frames",                      "1"                     },
-
-  { "sign_bullet",                             "RocksDC2.png"          },
-  { "sign_bullet.xpos",                                "12"                    },
-  { "sign_bullet.ypos",                                "2"                     },
-  { "sign_bullet.frames",                      "1"                     },
-
-  { "sign_heart",                              "RocksDC2.png"          },
-  { "sign_heart.xpos",                         "13"                    },
-  { "sign_heart.ypos",                         "2"                     },
-  { "sign_heart.frames",                       "1"                     },
-
-  { "sign_cross",                              "RocksDC2.png"          },
-  { "sign_cross.xpos",                         "14"                    },
-  { "sign_cross.ypos",                         "2"                     },
-  { "sign_cross.frames",                       "1"                     },
-
-  { "sign_frankie",                            "RocksDC2.png"          },
-  { "sign_frankie.xpos",                       "15"                    },
-  { "sign_frankie.ypos",                       "2"                     },
-  { "sign_frankie.frames",                     "1"                     },
-
-  { "landmine",                                        "RocksDC.png"           },
-  { "landmine.xpos",                           "7"                     },
-  { "landmine.ypos",                           "14"                    },
-  { "landmine.frames",                         "1"                     },
-  { "landmine.crumbled_like",                  "sand"                  },
-
-  { "dc_landmine",                             "RocksDC.png"           },
-  { "dc_landmine.xpos",                                "14"                    },
-  { "dc_landmine.ypos",                                "5"                     },
-  { "dc_landmine.frames",                      "1"                     },
-  { "dc_landmine.crumbled_like",               "sand"                  },
-
-  { "steelwall_slippery",                      "RocksDC.png"           },
-  { "steelwall_slippery.xpos",                 "5"                     },
-  { "steelwall_slippery.ypos",                 "15"                    },
-  { "steelwall_slippery.frames",               "1"                     },
-
-  { "extra_time",                              "RocksDC.png"           },
-  { "extra_time.xpos",                         "8"                     },
-  { "extra_time.ypos",                         "0"                     },
-  { "extra_time.frames",                       "6"                     },
-  { "extra_time.delay",                                "4"                     },
-  { "extra_time.collecting",                   "RocksCollect.png"      },
-  { "extra_time.collecting.xpos",              "7"                     },
-  { "extra_time.collecting.ypos",              "2"                     },
-  { "extra_time.collecting.frames",            "7"                     },
-  { "extra_time.collecting.anim_mode",         "linear"                },
-
-  { "shield_normal",                           "RocksDC.png"           },
-  { "shield_normal.xpos",                      "8"                     },
-  { "shield_normal.ypos",                      "2"                     },
-  { "shield_normal.frames",                    "6"                     },
-  { "shield_normal.delay",                     "4"                     },
-  { "shield_normal.active",                    "RocksHeroes.png"       },
-  { "shield_normal.active.xpos",               "1"                     },
-  { "shield_normal.active.ypos",               "13"                    },
-  { "shield_normal.active.frames",             "3"                     },
-  { "shield_normal.active.delay",              "8"                     },
-  { "shield_normal.active.anim_mode",          "pingpong"              },
-  { "shield_normal.collecting",                        "RocksCollect.png"      },
-  { "shield_normal.collecting.xpos",           "7"                     },
-  { "shield_normal.collecting.ypos",           "1"                     },
-  { "shield_normal.collecting.frames",         "7"                     },
-  { "shield_normal.collecting.anim_mode",      "linear"                },
-
-  { "shield_deadly",                           "RocksDC.png"           },
-  { "shield_deadly.xpos",                      "8"                     },
-  { "shield_deadly.ypos",                      "1"                     },
-  { "shield_deadly.frames",                    "6"                     },
-  { "shield_deadly.delay",                     "4"                     },
-  { "shield_deadly.active",                    "RocksHeroes.png"       },
-  { "shield_deadly.active.xpos",               "5"                     },
-  { "shield_deadly.active.ypos",               "13"                    },
-  { "shield_deadly.active.frames",             "3"                     },
-  { "shield_deadly.active.delay",              "8"                     },
-  { "shield_deadly.active.anim_mode",          "pingpong"              },
-  { "shield_deadly.collecting",                        "RocksCollect.png"      },
-  { "shield_deadly.collecting.xpos",           "7"                     },
-  { "shield_deadly.collecting.ypos",           "3"                     },
-  { "shield_deadly.collecting.frames",         "7"                     },
-  { "shield_deadly.collecting.anim_mode",      "linear"                },
-
-  { "switchgate_closed",                       "RocksDC.png"           },
-  { "switchgate_closed.xpos",                  "8"                     },
-  { "switchgate_closed.ypos",                  "5"                     },
-  { "switchgate_closed.frames",                        "1"                     },
-  { "switchgate.opening",                      "RocksDC.png"           },
-  { "switchgate.opening.xpos",                 "8"                     },
-  { "switchgate.opening.ypos",                 "5"                     },
-  { "switchgate.opening.frames",               "5"                     },
-  { "switchgate.opening.delay",                        "6"                     },
-  { "switchgate_open",                         "RocksDC.png"           },
-  { "switchgate_open.xpos",                    "12"                    },
-  { "switchgate_open.ypos",                    "5"                     },
-  { "switchgate_open.frames",                  "1"                     },
-  { "switchgate.closing",                      "RocksDC.png"           },
-  { "switchgate.closing.xpos",                 "8"                     },
-  { "switchgate.closing.ypos",                 "5"                     },
-  { "switchgate.closing.frames",               "5"                     },
-  { "switchgate.closing.delay",                        "6"                     },
-  { "switchgate.closing.anim_mode",            "reverse"               },
-
-  { "timegate_closed",                         "RocksDC.png"           },
-  { "timegate_closed.xpos",                    "8"                     },
-  { "timegate_closed.ypos",                    "6"                     },
-  { "timegate_closed.frames",                  "1"                     },
-  { "timegate.opening",                                "RocksDC.png"           },
-  { "timegate.opening.xpos",                   "8"                     },
-  { "timegate.opening.ypos",                   "6"                     },
-  { "timegate.opening.frames",                 "5"                     },
-  { "timegate.opening.delay",                  "6"                     },
-  { "timegate_open",                           "RocksDC.png"           },
-  { "timegate_open.xpos",                      "12"                    },
-  { "timegate_open.ypos",                      "6"                     },
-  { "timegate_open.frames",                    "1"                     },
-  { "timegate.closing",                                "RocksDC.png"           },
-  { "timegate.closing.xpos",                   "8"                     },
-  { "timegate.closing.ypos",                   "6"                     },
-  { "timegate.closing.frames",                 "5"                     },
-  { "timegate.closing.delay",                  "6"                     },
-  { "timegate.closing.anim_mode",              "reverse"               },
-
-  { "pearl",                                   "RocksDC.png"           },
-  { "pearl.xpos",                              "8"                     },
-  { "pearl.ypos",                              "11"                    },
-  { "pearl.frames",                            "1"                     },
-  { "pearl.breaking",                          "RocksDC.png"           },
-  { "pearl.breaking.xpos",                     "8"                     },
-  { "pearl.breaking.ypos",                     "12"                    },
-  { "pearl.breaking.frames",                   "4"                     },
-  { "pearl.breaking.delay",                    "2"                     },
-  { "pearl.breaking.anim_mode",                        "linear"                },
-  { "pearl.collecting",                                "RocksCollect.png"      },
-  { "pearl.collecting.xpos",                   "0"                     },
-  { "pearl.collecting.ypos",                   "16"                    },
-  { "pearl.collecting.frames",                 "7"                     },
-  { "pearl.collecting.anim_mode",              "linear"                },
-
-  { "crystal",                                 "RocksDC.png"           },
-  { "crystal.xpos",                            "9"                     },
-  { "crystal.ypos",                            "11"                    },
-  { "crystal.frames",                          "1"                     },
-  { "crystal.collecting",                      "RocksCollect.png"      },
-  { "crystal.collecting.xpos",                 "0"                     },
-  { "crystal.collecting.ypos",                 "17"                    },
-  { "crystal.collecting.frames",               "7"                     },
-  { "crystal.collecting.anim_mode",            "linear"                },
-
-  { "wall_pearl",                              "RocksDC.png"           },
-  { "wall_pearl.xpos",                         "10"                    },
-  { "wall_pearl.ypos",                         "11"                    },
-  { "wall_pearl.frames",                       "1"                     },
-
-  { "wall_crystal",                            "RocksDC.png"           },
-  { "wall_crystal.xpos",                       "11"                    },
-  { "wall_crystal.ypos",                       "11"                    },
-  { "wall_crystal.frames",                     "1"                     },
-
-  { "dc_steelwall_1_left",                     "RocksDC2.png"          },
-  { "dc_steelwall_1_left.xpos",                        "5"                     },
-  { "dc_steelwall_1_left.ypos",                        "1"                     },
-  { "dc_steelwall_1_left.frames",              "1"                     },
-  { "dc_steelwall_1_right",                    "RocksDC2.png"          },
-  { "dc_steelwall_1_right.xpos",               "3"                     },
-  { "dc_steelwall_1_right.ypos",               "1"                     },
-  { "dc_steelwall_1_right.frames",             "1"                     },
-  { "dc_steelwall_1_top",                      "RocksDC2.png"          },
-  { "dc_steelwall_1_top.xpos",                 "4"                     },
-  { "dc_steelwall_1_top.ypos",                 "2"                     },
-  { "dc_steelwall_1_top.frames",               "1"                     },
-  { "dc_steelwall_1_bottom",                   "RocksDC2.png"          },
-  { "dc_steelwall_1_bottom.xpos",              "4"                     },
-  { "dc_steelwall_1_bottom.ypos",              "0"                     },
-  { "dc_steelwall_1_bottom.frames",            "1"                     },
-  { "dc_steelwall_1_horizontal",               "RocksDC2.png"          },
-  { "dc_steelwall_1_horizontal.xpos",          "1"                     },
-  { "dc_steelwall_1_horizontal.ypos",          "0"                     },
-  { "dc_steelwall_1_horizontal.frames",                "1"                     },
-  { "dc_steelwall_1_vertical",                 "RocksDC2.png"          },
-  { "dc_steelwall_1_vertical.xpos",            "0"                     },
-  { "dc_steelwall_1_vertical.ypos",            "1"                     },
-  { "dc_steelwall_1_vertical.frames",          "1"                     },
-  { "dc_steelwall_1_topleft",                  "RocksDC2.png"          },
-  { "dc_steelwall_1_topleft.xpos",             "0"                     },
-  { "dc_steelwall_1_topleft.ypos",             "0"                     },
-  { "dc_steelwall_1_topleft.frames",           "1"                     },
-  { "dc_steelwall_1_topright",                 "RocksDC2.png"          },
-  { "dc_steelwall_1_topright.xpos",            "2"                     },
-  { "dc_steelwall_1_topright.ypos",            "0"                     },
-  { "dc_steelwall_1_topright.frames",          "1"                     },
-  { "dc_steelwall_1_bottomleft",               "RocksDC2.png"          },
-  { "dc_steelwall_1_bottomleft.xpos",          "0"                     },
-  { "dc_steelwall_1_bottomleft.ypos",          "2"                     },
-  { "dc_steelwall_1_bottomleft.frames",                "1"                     },
-  { "dc_steelwall_1_bottomright",              "RocksDC2.png"          },
-  { "dc_steelwall_1_bottomright.xpos",         "2"                     },
-  { "dc_steelwall_1_bottomright.ypos",         "2"                     },
-  { "dc_steelwall_1_bottomright.frames",       "1"                     },
-  { "dc_steelwall_1_topleft_2",                        "RocksDC2.png"          },
-  { "dc_steelwall_1_topleft_2.xpos",           "5"                     },
-  { "dc_steelwall_1_topleft_2.ypos",           "2"                     },
-  { "dc_steelwall_1_topleft_2.frames",         "1"                     },
-  { "dc_steelwall_1_topright_2",               "RocksDC2.png"          },
-  { "dc_steelwall_1_topright_2.xpos",          "3"                     },
-  { "dc_steelwall_1_topright_2.ypos",          "2"                     },
-  { "dc_steelwall_1_topright_2.frames",                "1"                     },
-  { "dc_steelwall_1_bottomleft_2",             "RocksDC2.png"          },
-  { "dc_steelwall_1_bottomleft_2.xpos",                "5"                     },
-  { "dc_steelwall_1_bottomleft_2.ypos",                "0"                     },
-  { "dc_steelwall_1_bottomleft_2.frames",      "1"                     },
-  { "dc_steelwall_1_bottomright_2",            "RocksDC2.png"          },
-  { "dc_steelwall_1_bottomright_2.xpos",       "3"                     },
-  { "dc_steelwall_1_bottomright_2.ypos",       "0"                     },
-  { "dc_steelwall_1_bottomright_2.frames",     "1"                     },
-
-  { "dc_steelwall_2_left",                     "RocksDC2.png"          },
-  { "dc_steelwall_2_left.xpos",                        "6"                     },
-  { "dc_steelwall_2_left.ypos",                        "1"                     },
-  { "dc_steelwall_2_left.frames",              "1"                     },
-  { "dc_steelwall_2_right",                    "RocksDC2.png"          },
-  { "dc_steelwall_2_right.xpos",               "9"                     },
-  { "dc_steelwall_2_right.ypos",               "1"                     },
-  { "dc_steelwall_2_right.frames",             "1"                     },
-  { "dc_steelwall_2_top",                      "RocksDC2.png"          },
-  { "dc_steelwall_2_top.xpos",                 "7"                     },
-  { "dc_steelwall_2_top.ypos",                 "0"                     },
-  { "dc_steelwall_2_top.frames",               "1"                     },
-  { "dc_steelwall_2_bottom",                   "RocksDC2.png"          },
-  { "dc_steelwall_2_bottom.xpos",              "7"                     },
-  { "dc_steelwall_2_bottom.ypos",              "3"                     },
-  { "dc_steelwall_2_bottom.frames",            "1"                     },
-  { "dc_steelwall_2_horizontal",               "RocksDC2.png"          },
-  { "dc_steelwall_2_horizontal.xpos",          "8"                     },
-  { "dc_steelwall_2_horizontal.ypos",          "1"                     },
-  { "dc_steelwall_2_horizontal.frames",                "1"                     },
-  { "dc_steelwall_2_vertical",                 "RocksDC2.png"          },
-  { "dc_steelwall_2_vertical.xpos",            "7"                     },
-  { "dc_steelwall_2_vertical.ypos",            "2"                     },
-  { "dc_steelwall_2_vertical.frames",          "1"                     },
-  { "dc_steelwall_2_middle",                   "RocksDC2.png"          },
-  { "dc_steelwall_2_middle.xpos",              "7"                     },
-  { "dc_steelwall_2_middle.ypos",              "1"                     },
-  { "dc_steelwall_2_middle.frames",            "1"                     },
-  { "dc_steelwall_2_single",                   "RocksDC2.png"          },
-  { "dc_steelwall_2_single.xpos",              "6"                     },
-  { "dc_steelwall_2_single.ypos",              "0"                     },
-  { "dc_steelwall_2_single.frames",            "1"                     },
+  { "invisible_steelwall",                             "RocksSP.png"                   },
+  { "invisible_steelwall.xpos",                                "3"                             },
+  { "invisible_steelwall.ypos",                                "5"                             },
+  { "invisible_steelwall.frames",                      "1"                             },
+  { "invisible_steelwall.EDITOR",                      "RocksSP.png"                   },
+  { "invisible_steelwall.EDITOR.xpos",                 "1"                             },
+  { "invisible_steelwall.EDITOR.ypos",                 "5"                             },
+  { "invisible_steelwall.active",                      "RocksSP.png"                   },
+  { "invisible_steelwall.active.xpos",                 "1"                             },
+  { "invisible_steelwall.active.ypos",                 "5"                             },
+  { "invisible_steelwall.active.frames",               "1"                             },
+
+  { "invisible_wall",                                  "RocksSP.png"                   },
+  { "invisible_wall.xpos",                             "7"                             },
+  { "invisible_wall.ypos",                             "5"                             },
+  { "invisible_wall.frames",                           "1"                             },
+  { "invisible_wall.EDITOR",                           "RocksSP.png"                   },
+  { "invisible_wall.EDITOR.xpos",                      "5"                             },
+  { "invisible_wall.EDITOR.ypos",                      "5"                             },
+  { "invisible_wall.active",                           "RocksSP.png"                   },
+  { "invisible_wall.active.xpos",                      "5"                             },
+  { "invisible_wall.active.ypos",                      "5"                             },
+  { "invisible_wall.active.frames",                    "1"                             },
+
+  { "invisible_sand",                                  "RocksSP.png"                   },
+  { "invisible_sand.xpos",                             "0"                             },
+  { "invisible_sand.ypos",                             "0"                             },
+  { "invisible_sand.frames",                           "1"                             },
+  { "invisible_sand.EDITOR",                           "RocksEMC.png"                  },
+  { "invisible_sand.EDITOR.xpos",                      "2"                             },
+  { "invisible_sand.EDITOR.ypos",                      "4"                             },
+  { "invisible_sand.active",                           "RocksEMC.png"                  },
+  { "invisible_sand.active.xpos",                      "2"                             },
+  { "invisible_sand.active.ypos",                      "4"                             },
+  { "invisible_sand.active.frames",                    "1"                             },
+  { "invisible_sand.active.CRUMBLED",                  "RocksEMC.png"                  },
+  { "invisible_sand.active.CRUMBLED.xpos",             "3"                             },
+  { "invisible_sand.active.CRUMBLED.ypos",             "4"                             },
+  { "invisible_sand.active.CRUMBLED.frames",           "1"                             },
+  { "invisible_sand.active.digging.left",              "RocksEMC.png"                  },
+  { "invisible_sand.active.digging.left.xpos",         "6"                             },
+  { "invisible_sand.active.digging.left.ypos",         "2"                             },
+  { "invisible_sand.active.digging.left.frames",       "3"                             },
+  { "invisible_sand.active.digging.left.delay",                "2"                             },
+  { "invisible_sand.active.digging.left.anim_mode",    "linear"                        },
+  { "invisible_sand.active.digging.right",             "RocksEMC.png"                  },
+  { "invisible_sand.active.digging.right.xpos",                "9"                             },
+  { "invisible_sand.active.digging.right.ypos",                "2"                             },
+  { "invisible_sand.active.digging.right.frames",      "3"                             },
+  { "invisible_sand.active.digging.right.delay",       "2"                             },
+  { "invisible_sand.active.digging.right.anim_mode",   "linear"                        },
+  { "invisible_sand.active.digging.up",                        "RocksEMC.png"                  },
+  { "invisible_sand.active.digging.up.xpos",           "0"                             },
+  { "invisible_sand.active.digging.up.ypos",           "2"                             },
+  { "invisible_sand.active.digging.up.frames",         "3"                             },
+  { "invisible_sand.active.digging.up.delay",          "2"                             },
+  { "invisible_sand.active.digging.up.anim_mode",      "linear"                        },
+  { "invisible_sand.active.digging.down",              "RocksEMC.png"                  },
+  { "invisible_sand.active.digging.down.xpos",         "3"                             },
+  { "invisible_sand.active.digging.down.ypos",         "2"                             },
+  { "invisible_sand.active.digging.down.frames",       "3"                             },
+  { "invisible_sand.active.digging.down.delay",                "2"                             },
+  { "invisible_sand.active.digging.down.anim_mode",    "linear"                        },
+  { "invisible_sand.active.digging.left.CRUMBLED",             "RocksEMC.png"          },
+  { "invisible_sand.active.digging.left.CRUMBLED.xpos",                "6"                     },
+  { "invisible_sand.active.digging.left.CRUMBLED.ypos",                "3"                     },
+  { "invisible_sand.active.digging.left.CRUMBLED.frames",      "3"                     },
+  { "invisible_sand.active.digging.left.CRUMBLED.delay",       "2"                     },
+  { "invisible_sand.active.digging.left.CRUMBLED.anim_mode",   "linear"                },
+  { "invisible_sand.active.digging.right.CRUMBLED",            "RocksEMC.png"          },
+  { "invisible_sand.active.digging.right.CRUMBLED.xpos",       "9"                     },
+  { "invisible_sand.active.digging.right.CRUMBLED.ypos",       "3"                     },
+  { "invisible_sand.active.digging.right.CRUMBLED.frames",     "3"                     },
+  { "invisible_sand.active.digging.right.CRUMBLED.delay",      "2"                     },
+  { "invisible_sand.active.digging.right.CRUMBLED.anim_mode",  "linear"                },
+  { "invisible_sand.active.digging.up.CRUMBLED",               "RocksEMC.png"          },
+  { "invisible_sand.active.digging.up.CRUMBLED.xpos",          "0"                     },
+  { "invisible_sand.active.digging.up.CRUMBLED.ypos",          "3"                     },
+  { "invisible_sand.active.digging.up.CRUMBLED.frames",                "3"                     },
+  { "invisible_sand.active.digging.up.CRUMBLED.delay",         "2"                     },
+  { "invisible_sand.active.digging.up.CRUMBLED.anim_mode",     "linear"                },
+  { "invisible_sand.active.digging.down.CRUMBLED",             "RocksEMC.png"          },
+  { "invisible_sand.active.digging.down.CRUMBLED.xpos",                "3"                     },
+  { "invisible_sand.active.digging.down.CRUMBLED.ypos",                "3"                     },
+  { "invisible_sand.active.digging.down.CRUMBLED.frames",      "3"                     },
+  { "invisible_sand.active.digging.down.CRUMBLED.delay",       "2"                     },
+  { "invisible_sand.active.digging.down.CRUMBLED.anim_mode",   "linear"                },
+
+  { "conveyor_belt_1_middle",                          "RocksDC.png"                   },
+  { "conveyor_belt_1_middle.xpos",                     "0"                             },
+  { "conveyor_belt_1_middle.ypos",                     "0"                             },
+  { "conveyor_belt_1_middle.frames",                   "1"                             },
+  { "conveyor_belt_1_middle.active",                   "RocksDC.png"                   },
+  { "conveyor_belt_1_middle.active.xpos",              "0"                             },
+  { "conveyor_belt_1_middle.active.ypos",              "0"                             },
+  { "conveyor_belt_1_middle.active.frames",            "8"                             },
+  { "conveyor_belt_1_middle.active.delay",             "2"                             },
+  { "conveyor_belt_1_left",                            "RocksDC.png"                   },
+  { "conveyor_belt_1_left.xpos",                       "0"                             },
+  { "conveyor_belt_1_left.ypos",                       "1"                             },
+  { "conveyor_belt_1_left.frames",                     "1"                             },
+  { "conveyor_belt_1_left.active",                     "RocksDC.png"                   },
+  { "conveyor_belt_1_left.active.xpos",                        "0"                             },
+  { "conveyor_belt_1_left.active.ypos",                        "1"                             },
+  { "conveyor_belt_1_left.active.frames",              "8"                             },
+  { "conveyor_belt_1_left.active.delay",               "2"                             },
+  { "conveyor_belt_1_right",                           "RocksDC.png"                   },
+  { "conveyor_belt_1_right.xpos",                      "0"                             },
+  { "conveyor_belt_1_right.ypos",                      "2"                             },
+  { "conveyor_belt_1_right.frames",                    "1"                             },
+  { "conveyor_belt_1_right.active",                    "RocksDC.png"                   },
+  { "conveyor_belt_1_right.active.xpos",               "0"                             },
+  { "conveyor_belt_1_right.active.ypos",               "2"                             },
+  { "conveyor_belt_1_right.active.frames",             "8"                             },
+  { "conveyor_belt_1_right.active.delay",              "2"                             },
+  { "conveyor_belt_1_switch_left",                     "RocksDC.png"                   },
+  { "conveyor_belt_1_switch_left.xpos",                        "0"                             },
+  { "conveyor_belt_1_switch_left.ypos",                        "12"                            },
+  { "conveyor_belt_1_switch_left.frames",              "1"                             },
+  { "conveyor_belt_1_switch_middle",                   "RocksDC.png"                   },
+  { "conveyor_belt_1_switch_middle.xpos",              "0"                             },
+  { "conveyor_belt_1_switch_middle.ypos",              "13"                            },
+  { "conveyor_belt_1_switch_middle.frames",            "1"                             },
+  { "conveyor_belt_1_switch_right",                    "RocksDC.png"                   },
+  { "conveyor_belt_1_switch_right.xpos",               "0"                             },
+  { "conveyor_belt_1_switch_right.ypos",               "14"                            },
+  { "conveyor_belt_1_switch_right.frames",             "1"                             },
+
+  { "conveyor_belt_2_middle",                          "RocksDC.png"                   },
+  { "conveyor_belt_2_middle.xpos",                     "0"                             },
+  { "conveyor_belt_2_middle.ypos",                     "3"                             },
+  { "conveyor_belt_2_middle.frames",                   "1"                             },
+  { "conveyor_belt_2_middle.active",                   "RocksDC.png"                   },
+  { "conveyor_belt_2_middle.active.xpos",              "0"                             },
+  { "conveyor_belt_2_middle.active.ypos",              "3"                             },
+  { "conveyor_belt_2_middle.active.frames",            "8"                             },
+  { "conveyor_belt_2_middle.active.delay",             "2"                             },
+  { "conveyor_belt_2_left",                            "RocksDC.png"                   },
+  { "conveyor_belt_2_left.xpos",                       "0"                             },
+  { "conveyor_belt_2_left.ypos",                       "4"                             },
+  { "conveyor_belt_2_left.frames",                     "1"                             },
+  { "conveyor_belt_2_left.active",                     "RocksDC.png"                   },
+  { "conveyor_belt_2_left.active.xpos",                        "0"                             },
+  { "conveyor_belt_2_left.active.ypos",                        "4"                             },
+  { "conveyor_belt_2_left.active.frames",              "8"                             },
+  { "conveyor_belt_2_left.active.delay",               "2"                             },
+  { "conveyor_belt_2_right",                           "RocksDC.png"                   },
+  { "conveyor_belt_2_right.xpos",                      "0"                             },
+  { "conveyor_belt_2_right.ypos",                      "5"                             },
+  { "conveyor_belt_2_right.frames",                    "1"                             },
+  { "conveyor_belt_2_right.active",                    "RocksDC.png"                   },
+  { "conveyor_belt_2_right.active.xpos",               "0"                             },
+  { "conveyor_belt_2_right.active.ypos",               "5"                             },
+  { "conveyor_belt_2_right.active.frames",             "8"                             },
+  { "conveyor_belt_2_right.active.delay",              "2"                             },
+  { "conveyor_belt_2_switch_left",                     "RocksDC.png"                   },
+  { "conveyor_belt_2_switch_left.xpos",                        "1"                             },
+  { "conveyor_belt_2_switch_left.ypos",                        "12"                            },
+  { "conveyor_belt_2_switch_left.frames",              "1"                             },
+  { "conveyor_belt_2_switch_middle",                   "RocksDC.png"                   },
+  { "conveyor_belt_2_switch_middle.xpos",              "1"                             },
+  { "conveyor_belt_2_switch_middle.ypos",              "13"                            },
+  { "conveyor_belt_2_switch_middle.frames",            "1"                             },
+  { "conveyor_belt_2_switch_right",                    "RocksDC.png"                   },
+  { "conveyor_belt_2_switch_right.xpos",               "1"                             },
+  { "conveyor_belt_2_switch_right.ypos",               "14"                            },
+  { "conveyor_belt_2_switch_right.frames",             "1"                             },
+
+  { "conveyor_belt_3_middle",                          "RocksDC.png"                   },
+  { "conveyor_belt_3_middle.xpos",                     "0"                             },
+  { "conveyor_belt_3_middle.ypos",                     "6"                             },
+  { "conveyor_belt_3_middle.frames",                   "1"                             },
+  { "conveyor_belt_3_middle.active",                   "RocksDC.png"                   },
+  { "conveyor_belt_3_middle.active.xpos",              "0"                             },
+  { "conveyor_belt_3_middle.active.ypos",              "6"                             },
+  { "conveyor_belt_3_middle.active.frames",            "8"                             },
+  { "conveyor_belt_3_middle.active.delay",             "2"                             },
+  { "conveyor_belt_3_left",                            "RocksDC.png"                   },
+  { "conveyor_belt_3_left.xpos",                       "0"                             },
+  { "conveyor_belt_3_left.ypos",                       "7"                             },
+  { "conveyor_belt_3_left.frames",                     "1"                             },
+  { "conveyor_belt_3_left.active",                     "RocksDC.png"                   },
+  { "conveyor_belt_3_left.active.xpos",                        "0"                             },
+  { "conveyor_belt_3_left.active.ypos",                        "7"                             },
+  { "conveyor_belt_3_left.active.frames",              "8"                             },
+  { "conveyor_belt_3_left.active.delay",               "2"                             },
+  { "conveyor_belt_3_right",                           "RocksDC.png"                   },
+  { "conveyor_belt_3_right.xpos",                      "0"                             },
+  { "conveyor_belt_3_right.ypos",                      "8"                             },
+  { "conveyor_belt_3_right.frames",                    "1"                             },
+  { "conveyor_belt_3_right.active",                    "RocksDC.png"                   },
+  { "conveyor_belt_3_right.active.xpos",               "0"                             },
+  { "conveyor_belt_3_right.active.ypos",               "8"                             },
+  { "conveyor_belt_3_right.active.frames",             "8"                             },
+  { "conveyor_belt_3_right.active.delay",              "2"                             },
+  { "conveyor_belt_3_switch_left",                     "RocksDC.png"                   },
+  { "conveyor_belt_3_switch_left.xpos",                        "2"                             },
+  { "conveyor_belt_3_switch_left.ypos",                        "12"                            },
+  { "conveyor_belt_3_switch_left.frames",              "1"                             },
+  { "conveyor_belt_3_switch_middle",                   "RocksDC.png"                   },
+  { "conveyor_belt_3_switch_middle.xpos",              "2"                             },
+  { "conveyor_belt_3_switch_middle.ypos",              "13"                            },
+  { "conveyor_belt_3_switch_middle.frames",            "1"                             },
+  { "conveyor_belt_3_switch_right",                    "RocksDC.png"                   },
+  { "conveyor_belt_3_switch_right.xpos",               "2"                             },
+  { "conveyor_belt_3_switch_right.ypos",               "14"                            },
+  { "conveyor_belt_3_switch_right.frames",             "1"                             },
+
+  { "conveyor_belt_4_middle",                          "RocksDC.png"                   },
+  { "conveyor_belt_4_middle.xpos",                     "0"                             },
+  { "conveyor_belt_4_middle.ypos",                     "9"                             },
+  { "conveyor_belt_4_middle.frames",                   "1"                             },
+  { "conveyor_belt_4_middle.active",                   "RocksDC.png"                   },
+  { "conveyor_belt_4_middle.active.xpos",              "0"                             },
+  { "conveyor_belt_4_middle.active.ypos",              "9"                             },
+  { "conveyor_belt_4_middle.active.frames",            "8"                             },
+  { "conveyor_belt_4_middle.active.delay",             "2"                             },
+  { "conveyor_belt_4_left",                            "RocksDC.png"                   },
+  { "conveyor_belt_4_left.xpos",                       "0"                             },
+  { "conveyor_belt_4_left.ypos",                       "10"                            },
+  { "conveyor_belt_4_left.frames",                     "1"                             },
+  { "conveyor_belt_4_left.active",                     "RocksDC.png"                   },
+  { "conveyor_belt_4_left.active.xpos",                        "0"                             },
+  { "conveyor_belt_4_left.active.ypos",                        "10"                            },
+  { "conveyor_belt_4_left.active.frames",              "8"                             },
+  { "conveyor_belt_4_left.active.delay",               "2"                             },
+  { "conveyor_belt_4_right",                           "RocksDC.png"                   },
+  { "conveyor_belt_4_right.xpos",                      "0"                             },
+  { "conveyor_belt_4_right.ypos",                      "11"                            },
+  { "conveyor_belt_4_right.frames",                    "1"                             },
+  { "conveyor_belt_4_right.active",                    "RocksDC.png"                   },
+  { "conveyor_belt_4_right.active.xpos",               "0"                             },
+  { "conveyor_belt_4_right.active.ypos",               "11"                            },
+  { "conveyor_belt_4_right.active.frames",             "8"                             },
+  { "conveyor_belt_4_right.active.delay",              "2"                             },
+  { "conveyor_belt_4_switch_left",                     "RocksDC.png"                   },
+  { "conveyor_belt_4_switch_left.xpos",                        "3"                             },
+  { "conveyor_belt_4_switch_left.ypos",                        "12"                            },
+  { "conveyor_belt_4_switch_left.frames",              "1"                             },
+  { "conveyor_belt_4_switch_middle",                   "RocksDC.png"                   },
+  { "conveyor_belt_4_switch_middle.xpos",              "3"                             },
+  { "conveyor_belt_4_switch_middle.ypos",              "13"                            },
+  { "conveyor_belt_4_switch_middle.frames",            "1"                             },
+  { "conveyor_belt_4_switch_right",                    "RocksDC.png"                   },
+  { "conveyor_belt_4_switch_right.xpos",               "3"                             },
+  { "conveyor_belt_4_switch_right.ypos",               "14"                            },
+  { "conveyor_belt_4_switch_right.frames",             "1"                             },
+
+  { "switchgate_switch_up",                            "RocksDC.png"                   },
+  { "switchgate_switch_up.xpos",                       "4"                             },
+  { "switchgate_switch_up.ypos",                       "12"                            },
+  { "switchgate_switch_up.frames",                     "1"                             },
+  { "switchgate_switch_down",                          "RocksDC.png"                   },
+  { "switchgate_switch_down.xpos",                     "5"                             },
+  { "switchgate_switch_down.ypos",                     "12"                            },
+  { "switchgate_switch_down.frames",                   "1"                             },
+
+  { "dc_switchgate_switch_up",                         "RocksDC2.png"                  },
+  { "dc_switchgate_switch_up.xpos",                    "10"                            },
+  { "dc_switchgate_switch_up.ypos",                    "1"                             },
+  { "dc_switchgate_switch_up.frames",                  "1"                             },
+  { "dc_switchgate_switch_down",                       "RocksDC2.png"                  },
+  { "dc_switchgate_switch_down.xpos",                  "11"                            },
+  { "dc_switchgate_switch_down.ypos",                  "1"                             },
+  { "dc_switchgate_switch_down.frames",                        "1"                             },
+
+  { "light_switch",                                    "RocksDC.png"                   },
+  { "light_switch.xpos",                               "6"                             },
+  { "light_switch.ypos",                               "12"                            },
+  { "light_switch.frames",                             "1"                             },
+  { "light_switch.active",                             "RocksDC.png"                   },
+  { "light_switch.active.xpos",                                "7"                             },
+  { "light_switch.active.ypos",                                "12"                            },
+  { "light_switch.active.frames",                      "1"                             },
+
+  { "timegate_switch",                                 "RocksDC.png"                   },
+  { "timegate_switch.xpos",                            "0"                             },
+  { "timegate_switch.ypos",                            "15"                            },
+  { "timegate_switch.frames",                          "1"                             },
+  { "timegate_switch.active",                          "RocksDC.png"                   },
+  { "timegate_switch.active.xpos",                     "0"                             },
+  { "timegate_switch.active.ypos",                     "15"                            },
+  { "timegate_switch.active.frames",                   "4"                             },
+
+  { "dc_timegate_switch",                              "RocksDC2.png"                  },
+  { "dc_timegate_switch.xpos",                         "12"                            },
+  { "dc_timegate_switch.ypos",                         "1"                             },
+  { "dc_timegate_switch.frames",                       "1"                             },
+  { "dc_timegate_switch.active",                       "RocksDC2.png"                  },
+  { "dc_timegate_switch.active.xpos",                  "12"                            },
+  { "dc_timegate_switch.active.ypos",                  "1"                             },
+  { "dc_timegate_switch.active.frames",                        "4"                             },
+
+  { "envelope_1",                                      "RocksMore.png"                 },
+  { "envelope_1.xpos",                                 "0"                             },
+  { "envelope_1.ypos",                                 "4"                             },
+  { "envelope_1.frames",                               "1"                             },
+  { "envelope_1.collecting",                           "RocksCollect.png"              },
+  { "envelope_1.collecting.xpos",                      "7"                             },
+  { "envelope_1.collecting.ypos",                      "8"                             },
+  { "envelope_1.collecting.frames",                    "7"                             },
+  { "envelope_1.collecting.anim_mode",                 "linear"                        },
+  { "envelope_2",                                      "RocksMore.png"                 },
+  { "envelope_2.xpos",                                 "1"                             },
+  { "envelope_2.ypos",                                 "4"                             },
+  { "envelope_2.frames",                               "1"                             },
+  { "envelope_2.collecting",                           "RocksCollect.png"              },
+  { "envelope_2.collecting.xpos",                      "7"                             },
+  { "envelope_2.collecting.ypos",                      "9"                             },
+  { "envelope_2.collecting.frames",                    "7"                             },
+  { "envelope_2.collecting.anim_mode",                 "linear"                        },
+  { "envelope_3",                                      "RocksMore.png"                 },
+  { "envelope_3.xpos",                                 "2"                             },
+  { "envelope_3.ypos",                                 "4"                             },
+  { "envelope_3.frames",                               "1"                             },
+  { "envelope_3.collecting",                           "RocksCollect.png"              },
+  { "envelope_3.collecting.xpos",                      "7"                             },
+  { "envelope_3.collecting.ypos",                      "10"                            },
+  { "envelope_3.collecting.frames",                    "7"                             },
+  { "envelope_3.collecting.anim_mode",                 "linear"                        },
+  { "envelope_4",                                      "RocksMore.png"                 },
+  { "envelope_4.xpos",                                 "3"                             },
+  { "envelope_4.ypos",                                 "4"                             },
+  { "envelope_4.frames",                               "1"                             },
+  { "envelope_4.collecting",                           "RocksCollect.png"              },
+  { "envelope_4.collecting.xpos",                      "7"                             },
+  { "envelope_4.collecting.ypos",                      "11"                            },
+  { "envelope_4.collecting.frames",                    "7"                             },
+  { "envelope_4.collecting.anim_mode",                 "linear"                        },
+
+  { "sign_radioactivity",                              "RocksDC.png"                   },
+  { "sign_radioactivity.xpos",                         "4"                             },
+  { "sign_radioactivity.ypos",                         "13"                            },
+  { "sign_radioactivity.frames",                       "1"                             },
+
+  { "sign_give_way",                                   "RocksDC.png"                   },
+  { "sign_give_way.xpos",                              "5"                             },
+  { "sign_give_way.ypos",                              "13"                            },
+  { "sign_give_way.frames",                            "1"                             },
+
+  { "sign_no_entry",                                   "RocksDC.png"                   },
+  { "sign_no_entry.xpos",                              "6"                             },
+  { "sign_no_entry.ypos",                              "13"                            },
+  { "sign_no_entry.frames",                            "1"                             },
+
+  { "sign_emergency_exit",                             "RocksDC.png"                   },
+  { "sign_emergency_exit.xpos",                                "7"                             },
+  { "sign_emergency_exit.ypos",                                "13"                            },
+  { "sign_emergency_exit.frames",                      "1"                             },
+
+  { "sign_yin_yang",                                   "RocksDC.png"                   },
+  { "sign_yin_yang.xpos",                              "4"                             },
+  { "sign_yin_yang.ypos",                              "14"                            },
+  { "sign_yin_yang.frames",                            "1"                             },
+
+  { "sign_exclamation",                                        "RocksDC.png"                   },
+  { "sign_exclamation.xpos",                           "5"                             },
+  { "sign_exclamation.ypos",                           "14"                            },
+  { "sign_exclamation.frames",                         "1"                             },
+
+  { "sign_stop",                                       "RocksDC.png"                   },
+  { "sign_stop.xpos",                                  "6"                             },
+  { "sign_stop.ypos",                                  "14"                            },
+  { "sign_stop.frames",                                        "1"                             },
+
+  { "sign_parking",                                    "RocksDC.png"                   },
+  { "sign_parking.xpos",                               "6"                             },
+  { "sign_parking.ypos",                               "15"                            },
+  { "sign_parking.frames",                             "1"                             },
+
+  { "sign_wheelchair",                                 "RocksDC.png"                   },
+  { "sign_wheelchair.xpos",                            "7"                             },
+  { "sign_wheelchair.ypos",                            "15"                            },
+  { "sign_wheelchair.frames",                          "1"                             },
+
+  { "sign_entry_forbidden",                            "RocksDC.png"                   },
+  { "sign_entry_forbidden.xpos",                       "12"                            },
+  { "sign_entry_forbidden.ypos",                       "15"                            },
+  { "sign_entry_forbidden.frames",                     "1"                             },
+
+  { "sperms",                                          "RocksDC2.png"                  },
+  { "sperms.xpos",                                     "11"                            },
+  { "sperms.ypos",                                     "3"                             },
+  { "sperms.frames",                                   "1"                             },
+
+  { "bullet",                                          "RocksDC2.png"                  },
+  { "bullet.xpos",                                     "12"                            },
+  { "bullet.ypos",                                     "3"                             },
+  { "bullet.frames",                                   "1"                             },
+
+  { "heart",                                           "RocksDC2.png"                  },
+  { "heart.xpos",                                      "13"                            },
+  { "heart.ypos",                                      "3"                             },
+  { "heart.frames",                                    "1"                             },
+
+  { "cross",                                           "RocksDC2.png"                  },
+  { "cross.xpos",                                      "14"                            },
+  { "cross.ypos",                                      "3"                             },
+  { "cross.frames",                                    "1"                             },
+
+  { "frankie",                                         "RocksDC2.png"                  },
+  { "frankie.xpos",                                    "15"                            },
+  { "frankie.ypos",                                    "3"                             },
+  { "frankie.frames",                                  "1"                             },
+
+  { "sign_sperms",                                     "RocksDC2.png"                  },
+  { "sign_sperms.xpos",                                        "11"                            },
+  { "sign_sperms.ypos",                                        "2"                             },
+  { "sign_sperms.frames",                              "1"                             },
+
+  { "sign_bullet",                                     "RocksDC2.png"                  },
+  { "sign_bullet.xpos",                                        "12"                            },
+  { "sign_bullet.ypos",                                        "2"                             },
+  { "sign_bullet.frames",                              "1"                             },
+
+  { "sign_heart",                                      "RocksDC2.png"                  },
+  { "sign_heart.xpos",                                 "13"                            },
+  { "sign_heart.ypos",                                 "2"                             },
+  { "sign_heart.frames",                               "1"                             },
+
+  { "sign_cross",                                      "RocksDC2.png"                  },
+  { "sign_cross.xpos",                                 "14"                            },
+  { "sign_cross.ypos",                                 "2"                             },
+  { "sign_cross.frames",                               "1"                             },
+
+  { "sign_frankie",                                    "RocksDC2.png"                  },
+  { "sign_frankie.xpos",                               "15"                            },
+  { "sign_frankie.ypos",                               "2"                             },
+  { "sign_frankie.frames",                             "1"                             },
+
+  { "landmine",                                                "RocksDC.png"                   },
+  { "landmine.xpos",                                   "7"                             },
+  { "landmine.ypos",                                   "14"                            },
+  { "landmine.frames",                                 "1"                             },
+  { "landmine.crumbled_like",                          "sand"                          },
+
+  { "dc_landmine",                                     "RocksDC.png"                   },
+  { "dc_landmine.xpos",                                        "14"                            },
+  { "dc_landmine.ypos",                                        "5"                             },
+  { "dc_landmine.frames",                              "1"                             },
+  { "dc_landmine.crumbled_like",                       "sand"                          },
+
+  { "steelwall_slippery",                              "RocksDC.png"                   },
+  { "steelwall_slippery.xpos",                         "5"                             },
+  { "steelwall_slippery.ypos",                         "15"                            },
+  { "steelwall_slippery.frames",                       "1"                             },
+
+  { "extra_time",                                      "RocksDC.png"                   },
+  { "extra_time.xpos",                                 "8"                             },
+  { "extra_time.ypos",                                 "0"                             },
+  { "extra_time.frames",                               "6"                             },
+  { "extra_time.delay",                                        "4"                             },
+  { "extra_time.collecting",                           "RocksCollect.png"              },
+  { "extra_time.collecting.xpos",                      "7"                             },
+  { "extra_time.collecting.ypos",                      "2"                             },
+  { "extra_time.collecting.frames",                    "7"                             },
+  { "extra_time.collecting.anim_mode",                 "linear"                        },
+
+  { "shield_normal",                                   "RocksDC.png"                   },
+  { "shield_normal.xpos",                              "8"                             },
+  { "shield_normal.ypos",                              "2"                             },
+  { "shield_normal.frames",                            "6"                             },
+  { "shield_normal.delay",                             "4"                             },
+  { "shield_normal.active",                            "RocksHeroes.png"               },
+  { "shield_normal.active.xpos",                       "1"                             },
+  { "shield_normal.active.ypos",                       "13"                            },
+  { "shield_normal.active.frames",                     "3"                             },
+  { "shield_normal.active.delay",                      "8"                             },
+  { "shield_normal.active.anim_mode",                  "pingpong"                      },
+  { "shield_normal.collecting",                                "RocksCollect.png"              },
+  { "shield_normal.collecting.xpos",                   "7"                             },
+  { "shield_normal.collecting.ypos",                   "1"                             },
+  { "shield_normal.collecting.frames",                 "7"                             },
+  { "shield_normal.collecting.anim_mode",              "linear"                        },
+
+  { "shield_deadly",                                   "RocksDC.png"                   },
+  { "shield_deadly.xpos",                              "8"                             },
+  { "shield_deadly.ypos",                              "1"                             },
+  { "shield_deadly.frames",                            "6"                             },
+  { "shield_deadly.delay",                             "4"                             },
+  { "shield_deadly.active",                            "RocksHeroes.png"               },
+  { "shield_deadly.active.xpos",                       "5"                             },
+  { "shield_deadly.active.ypos",                       "13"                            },
+  { "shield_deadly.active.frames",                     "3"                             },
+  { "shield_deadly.active.delay",                      "8"                             },
+  { "shield_deadly.active.anim_mode",                  "pingpong"                      },
+  { "shield_deadly.collecting",                                "RocksCollect.png"              },
+  { "shield_deadly.collecting.xpos",                   "7"                             },
+  { "shield_deadly.collecting.ypos",                   "3"                             },
+  { "shield_deadly.collecting.frames",                 "7"                             },
+  { "shield_deadly.collecting.anim_mode",              "linear"                        },
+
+  { "switchgate_closed",                               "RocksDC.png"                   },
+  { "switchgate_closed.xpos",                          "8"                             },
+  { "switchgate_closed.ypos",                          "5"                             },
+  { "switchgate_closed.frames",                                "1"                             },
+  { "switchgate.opening",                              "RocksDC.png"                   },
+  { "switchgate.opening.xpos",                         "8"                             },
+  { "switchgate.opening.ypos",                         "5"                             },
+  { "switchgate.opening.frames",                       "5"                             },
+  { "switchgate.opening.delay",                                "6"                             },
+  { "switchgate_open",                                 "RocksDC.png"                   },
+  { "switchgate_open.xpos",                            "12"                            },
+  { "switchgate_open.ypos",                            "5"                             },
+  { "switchgate_open.frames",                          "1"                             },
+  { "switchgate.closing",                              "RocksDC.png"                   },
+  { "switchgate.closing.xpos",                         "8"                             },
+  { "switchgate.closing.ypos",                         "5"                             },
+  { "switchgate.closing.frames",                       "5"                             },
+  { "switchgate.closing.delay",                                "6"                             },
+  { "switchgate.closing.anim_mode",                    "reverse"                       },
+
+  { "timegate_closed",                                 "RocksDC.png"                   },
+  { "timegate_closed.xpos",                            "8"                             },
+  { "timegate_closed.ypos",                            "6"                             },
+  { "timegate_closed.frames",                          "1"                             },
+  { "timegate.opening",                                        "RocksDC.png"                   },
+  { "timegate.opening.xpos",                           "8"                             },
+  { "timegate.opening.ypos",                           "6"                             },
+  { "timegate.opening.frames",                         "5"                             },
+  { "timegate.opening.delay",                          "6"                             },
+  { "timegate_open",                                   "RocksDC.png"                   },
+  { "timegate_open.xpos",                              "12"                            },
+  { "timegate_open.ypos",                              "6"                             },
+  { "timegate_open.frames",                            "1"                             },
+  { "timegate.closing",                                        "RocksDC.png"                   },
+  { "timegate.closing.xpos",                           "8"                             },
+  { "timegate.closing.ypos",                           "6"                             },
+  { "timegate.closing.frames",                         "5"                             },
+  { "timegate.closing.delay",                          "6"                             },
+  { "timegate.closing.anim_mode",                      "reverse"                       },
+
+  { "pearl",                                           "RocksDC.png"                   },
+  { "pearl.xpos",                                      "8"                             },
+  { "pearl.ypos",                                      "11"                            },
+  { "pearl.frames",                                    "1"                             },
+  { "pearl.breaking",                                  "RocksDC.png"                   },
+  { "pearl.breaking.xpos",                             "8"                             },
+  { "pearl.breaking.ypos",                             "12"                            },
+  { "pearl.breaking.frames",                           "4"                             },
+  { "pearl.breaking.delay",                            "2"                             },
+  { "pearl.breaking.anim_mode",                                "linear"                        },
+  { "pearl.collecting",                                        "RocksCollect.png"              },
+  { "pearl.collecting.xpos",                           "0"                             },
+  { "pearl.collecting.ypos",                           "16"                            },
+  { "pearl.collecting.frames",                         "7"                             },
+  { "pearl.collecting.anim_mode",                      "linear"                        },
+
+  { "crystal",                                         "RocksDC.png"                   },
+  { "crystal.xpos",                                    "9"                             },
+  { "crystal.ypos",                                    "11"                            },
+  { "crystal.frames",                                  "1"                             },
+  { "crystal.collecting",                              "RocksCollect.png"              },
+  { "crystal.collecting.xpos",                         "0"                             },
+  { "crystal.collecting.ypos",                         "17"                            },
+  { "crystal.collecting.frames",                       "7"                             },
+  { "crystal.collecting.anim_mode",                    "linear"                        },
+
+  { "wall_pearl",                                      "RocksDC.png"                   },
+  { "wall_pearl.xpos",                                 "10"                            },
+  { "wall_pearl.ypos",                                 "11"                            },
+  { "wall_pearl.frames",                               "1"                             },
+
+  { "wall_crystal",                                    "RocksDC.png"                   },
+  { "wall_crystal.xpos",                               "11"                            },
+  { "wall_crystal.ypos",                               "11"                            },
+  { "wall_crystal.frames",                             "1"                             },
+
+  { "dc_steelwall_1_left",                             "RocksDC2.png"                  },
+  { "dc_steelwall_1_left.xpos",                                "5"                             },
+  { "dc_steelwall_1_left.ypos",                                "1"                             },
+  { "dc_steelwall_1_left.frames",                      "1"                             },
+  { "dc_steelwall_1_right",                            "RocksDC2.png"                  },
+  { "dc_steelwall_1_right.xpos",                       "3"                             },
+  { "dc_steelwall_1_right.ypos",                       "1"                             },
+  { "dc_steelwall_1_right.frames",                     "1"                             },
+  { "dc_steelwall_1_top",                              "RocksDC2.png"                  },
+  { "dc_steelwall_1_top.xpos",                         "4"                             },
+  { "dc_steelwall_1_top.ypos",                         "2"                             },
+  { "dc_steelwall_1_top.frames",                       "1"                             },
+  { "dc_steelwall_1_bottom",                           "RocksDC2.png"                  },
+  { "dc_steelwall_1_bottom.xpos",                      "4"                             },
+  { "dc_steelwall_1_bottom.ypos",                      "0"                             },
+  { "dc_steelwall_1_bottom.frames",                    "1"                             },
+  { "dc_steelwall_1_horizontal",                       "RocksDC2.png"                  },
+  { "dc_steelwall_1_horizontal.xpos",                  "1"                             },
+  { "dc_steelwall_1_horizontal.ypos",                  "0"                             },
+  { "dc_steelwall_1_horizontal.frames",                        "1"                             },
+  { "dc_steelwall_1_vertical",                         "RocksDC2.png"                  },
+  { "dc_steelwall_1_vertical.xpos",                    "0"                             },
+  { "dc_steelwall_1_vertical.ypos",                    "1"                             },
+  { "dc_steelwall_1_vertical.frames",                  "1"                             },
+  { "dc_steelwall_1_topleft",                          "RocksDC2.png"                  },
+  { "dc_steelwall_1_topleft.xpos",                     "0"                             },
+  { "dc_steelwall_1_topleft.ypos",                     "0"                             },
+  { "dc_steelwall_1_topleft.frames",                   "1"                             },
+  { "dc_steelwall_1_topright",                         "RocksDC2.png"                  },
+  { "dc_steelwall_1_topright.xpos",                    "2"                             },
+  { "dc_steelwall_1_topright.ypos",                    "0"                             },
+  { "dc_steelwall_1_topright.frames",                  "1"                             },
+  { "dc_steelwall_1_bottomleft",                       "RocksDC2.png"                  },
+  { "dc_steelwall_1_bottomleft.xpos",                  "0"                             },
+  { "dc_steelwall_1_bottomleft.ypos",                  "2"                             },
+  { "dc_steelwall_1_bottomleft.frames",                        "1"                             },
+  { "dc_steelwall_1_bottomright",                      "RocksDC2.png"                  },
+  { "dc_steelwall_1_bottomright.xpos",                 "2"                             },
+  { "dc_steelwall_1_bottomright.ypos",                 "2"                             },
+  { "dc_steelwall_1_bottomright.frames",               "1"                             },
+  { "dc_steelwall_1_topleft_2",                                "RocksDC2.png"                  },
+  { "dc_steelwall_1_topleft_2.xpos",                   "5"                             },
+  { "dc_steelwall_1_topleft_2.ypos",                   "2"                             },
+  { "dc_steelwall_1_topleft_2.frames",                 "1"                             },
+  { "dc_steelwall_1_topright_2",                       "RocksDC2.png"                  },
+  { "dc_steelwall_1_topright_2.xpos",                  "3"                             },
+  { "dc_steelwall_1_topright_2.ypos",                  "2"                             },
+  { "dc_steelwall_1_topright_2.frames",                        "1"                             },
+  { "dc_steelwall_1_bottomleft_2",                     "RocksDC2.png"                  },
+  { "dc_steelwall_1_bottomleft_2.xpos",                        "5"                             },
+  { "dc_steelwall_1_bottomleft_2.ypos",                        "0"                             },
+  { "dc_steelwall_1_bottomleft_2.frames",              "1"                             },
+  { "dc_steelwall_1_bottomright_2",                    "RocksDC2.png"                  },
+  { "dc_steelwall_1_bottomright_2.xpos",               "3"                             },
+  { "dc_steelwall_1_bottomright_2.ypos",               "0"                             },
+  { "dc_steelwall_1_bottomright_2.frames",             "1"                             },
+
+  { "dc_steelwall_2_left",                             "RocksDC2.png"                  },
+  { "dc_steelwall_2_left.xpos",                                "6"                             },
+  { "dc_steelwall_2_left.ypos",                                "1"                             },
+  { "dc_steelwall_2_left.frames",                      "1"                             },
+  { "dc_steelwall_2_right",                            "RocksDC2.png"                  },
+  { "dc_steelwall_2_right.xpos",                       "9"                             },
+  { "dc_steelwall_2_right.ypos",                       "1"                             },
+  { "dc_steelwall_2_right.frames",                     "1"                             },
+  { "dc_steelwall_2_top",                              "RocksDC2.png"                  },
+  { "dc_steelwall_2_top.xpos",                         "7"                             },
+  { "dc_steelwall_2_top.ypos",                         "0"                             },
+  { "dc_steelwall_2_top.frames",                       "1"                             },
+  { "dc_steelwall_2_bottom",                           "RocksDC2.png"                  },
+  { "dc_steelwall_2_bottom.xpos",                      "7"                             },
+  { "dc_steelwall_2_bottom.ypos",                      "3"                             },
+  { "dc_steelwall_2_bottom.frames",                    "1"                             },
+  { "dc_steelwall_2_horizontal",                       "RocksDC2.png"                  },
+  { "dc_steelwall_2_horizontal.xpos",                  "8"                             },
+  { "dc_steelwall_2_horizontal.ypos",                  "1"                             },
+  { "dc_steelwall_2_horizontal.frames",                        "1"                             },
+  { "dc_steelwall_2_vertical",                         "RocksDC2.png"                  },
+  { "dc_steelwall_2_vertical.xpos",                    "7"                             },
+  { "dc_steelwall_2_vertical.ypos",                    "2"                             },
+  { "dc_steelwall_2_vertical.frames",                  "1"                             },
+  { "dc_steelwall_2_middle",                           "RocksDC2.png"                  },
+  { "dc_steelwall_2_middle.xpos",                      "7"                             },
+  { "dc_steelwall_2_middle.ypos",                      "1"                             },
+  { "dc_steelwall_2_middle.frames",                    "1"                             },
+  { "dc_steelwall_2_single",                           "RocksDC2.png"                  },
+  { "dc_steelwall_2_single.xpos",                      "6"                             },
+  { "dc_steelwall_2_single.ypos",                      "0"                             },
+  { "dc_steelwall_2_single.frames",                    "1"                             },
 
   // images for DX Boulderdash style elements and actions
 
-  { "tube_right_down",                         "RocksDC.png"           },
-  { "tube_right_down.xpos",                    "9"                     },
-  { "tube_right_down.ypos",                    "13"                    },
-  { "tube_right_down.frames",                  "1"                     },
-
-  { "tube_horizontal_down",                    "RocksDC.png"           },
-  { "tube_horizontal_down.xpos",               "10"                    },
-  { "tube_horizontal_down.ypos",               "13"                    },
-  { "tube_horizontal_down.frames",             "1"                     },
-
-  { "tube_left_down",                          "RocksDC.png"           },
-  { "tube_left_down.xpos",                     "11"                    },
-  { "tube_left_down.ypos",                     "13"                    },
-  { "tube_left_down.frames",                   "1"                     },
-
-  { "tube_horizontal",                         "RocksDC.png"           },
-  { "tube_horizontal.xpos",                    "8"                     },
-  { "tube_horizontal.ypos",                    "14"                    },
-  { "tube_horizontal.frames",                  "1"                     },
-
-  { "tube_vertical_right",                     "RocksDC.png"           },
-  { "tube_vertical_right.xpos",                        "9"                     },
-  { "tube_vertical_right.ypos",                        "14"                    },
-  { "tube_vertical_right.frames",              "1"                     },
-
-  { "tube_any",                                        "RocksDC.png"           },
-  { "tube_any.xpos",                           "10"                    },
-  { "tube_any.ypos",                           "14"                    },
-  { "tube_any.frames",                         "1"                     },
-
-  { "tube_vertical_left",                      "RocksDC.png"           },
-  { "tube_vertical_left.xpos",                 "11"                    },
-  { "tube_vertical_left.ypos",                 "14"                    },
-  { "tube_vertical_left.frames",               "1"                     },
-
-  { "tube_vertical",                           "RocksDC.png"           },
-  { "tube_vertical.xpos",                      "8"                     },
-  { "tube_vertical.ypos",                      "15"                    },
-  { "tube_vertical.frames",                    "1"                     },
-
-  { "tube_right_up",                           "RocksDC.png"           },
-  { "tube_right_up.xpos",                      "9"                     },
-  { "tube_right_up.ypos",                      "15"                    },
-  { "tube_right_up.frames",                    "1"                     },
-
-  { "tube_horizontal_up",                      "RocksDC.png"           },
-  { "tube_horizontal_up.xpos",                 "10"                    },
-  { "tube_horizontal_up.ypos",                 "15"                    },
-  { "tube_horizontal_up.frames",               "1"                     },
-
-  { "tube_left_up",                            "RocksDC.png"           },
-  { "tube_left_up.xpos",                       "11"                    },
-  { "tube_left_up.ypos",                       "15"                    },
-  { "tube_left_up.frames",                     "1"                     },
-
-  { "trap",                                    "RocksDC.png"           },
-  { "trap.xpos",                               "12"                    },
-  { "trap.ypos",                               "8"                     },
-  { "trap.frames",                             "1"                     },
-  { "trap.crumbled_like",                      "sand"                  },
-  { "trap.diggable_like",                      "sand"                  },
-  { "trap.active",                             "RocksDC.png"           },
-  { "trap.active.xpos",                                "12"                    },
-  { "trap.active.ypos",                                "8"                     },
-  { "trap.active.frames",                      "4"                     },
-  { "trap.active.delay",                       "4"                     },
-  { "trap.active.anim_mode",                   "pingpong2"             },
-  { "trap.active.crumbled_like",               "sand"                  },
-
-  { "dx_supabomb",                             "RocksDC.png"           },
-  { "dx_supabomb.xpos",                                "15"                    },
-  { "dx_supabomb.ypos",                                "9"                     },
-  { "dx_supabomb.frames",                      "1"                     },
+  { "tube_right_down",                                 "RocksDC.png"                   },
+  { "tube_right_down.xpos",                            "9"                             },
+  { "tube_right_down.ypos",                            "13"                            },
+  { "tube_right_down.frames",                          "1"                             },
+
+  { "tube_horizontal_down",                            "RocksDC.png"                   },
+  { "tube_horizontal_down.xpos",                       "10"                            },
+  { "tube_horizontal_down.ypos",                       "13"                            },
+  { "tube_horizontal_down.frames",                     "1"                             },
+
+  { "tube_left_down",                                  "RocksDC.png"                   },
+  { "tube_left_down.xpos",                             "11"                            },
+  { "tube_left_down.ypos",                             "13"                            },
+  { "tube_left_down.frames",                           "1"                             },
+
+  { "tube_horizontal",                                 "RocksDC.png"                   },
+  { "tube_horizontal.xpos",                            "8"                             },
+  { "tube_horizontal.ypos",                            "14"                            },
+  { "tube_horizontal.frames",                          "1"                             },
+
+  { "tube_vertical_right",                             "RocksDC.png"                   },
+  { "tube_vertical_right.xpos",                                "9"                             },
+  { "tube_vertical_right.ypos",                                "14"                            },
+  { "tube_vertical_right.frames",                      "1"                             },
+
+  { "tube_any",                                                "RocksDC.png"                   },
+  { "tube_any.xpos",                                   "10"                            },
+  { "tube_any.ypos",                                   "14"                            },
+  { "tube_any.frames",                                 "1"                             },
+
+  { "tube_vertical_left",                              "RocksDC.png"                   },
+  { "tube_vertical_left.xpos",                         "11"                            },
+  { "tube_vertical_left.ypos",                         "14"                            },
+  { "tube_vertical_left.frames",                       "1"                             },
+
+  { "tube_vertical",                                   "RocksDC.png"                   },
+  { "tube_vertical.xpos",                              "8"                             },
+  { "tube_vertical.ypos",                              "15"                            },
+  { "tube_vertical.frames",                            "1"                             },
+
+  { "tube_right_up",                                   "RocksDC.png"                   },
+  { "tube_right_up.xpos",                              "9"                             },
+  { "tube_right_up.ypos",                              "15"                            },
+  { "tube_right_up.frames",                            "1"                             },
+
+  { "tube_horizontal_up",                              "RocksDC.png"                   },
+  { "tube_horizontal_up.xpos",                         "10"                            },
+  { "tube_horizontal_up.ypos",                         "15"                            },
+  { "tube_horizontal_up.frames",                       "1"                             },
+
+  { "tube_left_up",                                    "RocksDC.png"                   },
+  { "tube_left_up.xpos",                               "11"                            },
+  { "tube_left_up.ypos",                               "15"                            },
+  { "tube_left_up.frames",                             "1"                             },
+
+  { "trap",                                            "RocksDC.png"                   },
+  { "trap.xpos",                                       "12"                            },
+  { "trap.ypos",                                       "8"                             },
+  { "trap.frames",                                     "1"                             },
+  { "trap.crumbled_like",                              "sand"                          },
+  { "trap.diggable_like",                              "sand"                          },
+  { "trap.active",                                     "RocksDC.png"                   },
+  { "trap.active.xpos",                                        "12"                            },
+  { "trap.active.ypos",                                        "8"                             },
+  { "trap.active.frames",                              "4"                             },
+  { "trap.active.delay",                               "4"                             },
+  { "trap.active.anim_mode",                           "pingpong2"                     },
+  { "trap.active.crumbled_like",                       "sand"                          },
+
+  { "dx_supabomb",                                     "RocksDC.png"                   },
+  { "dx_supabomb.xpos",                                        "15"                            },
+  { "dx_supabomb.ypos",                                        "9"                             },
+  { "dx_supabomb.frames",                              "1"                             },
 
   // images for Rocks'n'Diamonds style elements and actions
 
-  { "key_1",                                   "RocksElements.png"     },
-  { "key_1.xpos",                              "4"                     },
-  { "key_1.ypos",                              "1"                     },
-  { "key_1.frames",                            "1"                     },
-  { "key_1.collecting",                                "RocksCollect.png"      },
-  { "key_1.collecting.xpos",                   "0"                     },
-  { "key_1.collecting.ypos",                   "3"                     },
-  { "key_1.collecting.frames",                 "7"                     },
-  { "key_1.collecting.anim_mode",              "linear"                },
-  { "key_2",                                   "RocksElements.png"     },
-  { "key_2.xpos",                              "5"                     },
-  { "key_2.ypos",                              "1"                     },
-  { "key_2.frames",                            "1"                     },
-  { "key_2.collecting",                                "RocksCollect.png"      },
-  { "key_2.collecting.xpos",                   "0"                     },
-  { "key_2.collecting.ypos",                   "4"                     },
-  { "key_2.collecting.frames",                 "7"                     },
-  { "key_2.collecting.anim_mode",              "linear"                },
-  { "key_3",                                   "RocksElements.png"     },
-  { "key_3.xpos",                              "6"                     },
-  { "key_3.ypos",                              "1"                     },
-  { "key_3.frames",                            "1"                     },
-  { "key_3.collecting",                                "RocksCollect.png"      },
-  { "key_3.collecting.xpos",                   "0"                     },
-  { "key_3.collecting.ypos",                   "5"                     },
-  { "key_3.collecting.frames",                 "7"                     },
-  { "key_3.collecting.anim_mode",              "linear"                },
-  { "key_4",                                   "RocksElements.png"     },
-  { "key_4.xpos",                              "7"                     },
-  { "key_4.ypos",                              "1"                     },
-  { "key_4.frames",                            "1"                     },
-  { "key_4.collecting",                                "RocksCollect.png"      },
-  { "key_4.collecting.xpos",                   "0"                     },
-  { "key_4.collecting.ypos",                   "6"                     },
-  { "key_4.collecting.frames",                 "7"                     },
-  { "key_4.collecting.anim_mode",              "linear"                },
-
-  { "gate_1",                                  "RocksElements.png"     },
-  { "gate_1.xpos",                             "4"                     },
-  { "gate_1.ypos",                             "2"                     },
-  { "gate_1.frames",                           "1"                     },
-  { "gate_2",                                  "RocksElements.png"     },
-  { "gate_2.xpos",                             "5"                     },
-  { "gate_2.ypos",                             "2"                     },
-  { "gate_2.frames",                           "1"                     },
-  { "gate_3",                                  "RocksElements.png"     },
-  { "gate_3.xpos",                             "6"                     },
-  { "gate_3.ypos",                             "2"                     },
-  { "gate_3.frames",                           "1"                     },
-  { "gate_4",                                  "RocksElements.png"     },
-  { "gate_4.xpos",                             "7"                     },
-  { "gate_4.ypos",                             "2"                     },
-  { "gate_4.frames",                           "1"                     },
-  { "gate_1_gray",                             "RocksElements.png"     },
-  { "gate_1_gray.xpos",                                "8"                     },
-  { "gate_1_gray.ypos",                                "2"                     },
-  { "gate_1_gray.frames",                      "1"                     },
-  { "gate_1_gray.EDITOR",                      "RocksElements.png"     },
-  { "gate_1_gray.EDITOR.xpos",                 "8"                     },
-  { "gate_1_gray.EDITOR.ypos",                 "14"                    },
-  { "gate_1_gray.active",                      "RocksElements.png"     },
-  { "gate_1_gray.active.xpos",                 "4"                     },
-  { "gate_1_gray.active.ypos",                 "2"                     },
-  { "gate_1_gray.active.frames",               "1"                     },
-  { "gate_2_gray",                             "RocksElements.png"     },
-  { "gate_2_gray.xpos",                                "9"                     },
-  { "gate_2_gray.ypos",                                "2"                     },
-  { "gate_2_gray.frames",                      "1"                     },
-  { "gate_2_gray.EDITOR",                      "RocksElements.png"     },
-  { "gate_2_gray.EDITOR.xpos",                 "9"                     },
-  { "gate_2_gray.EDITOR.ypos",                 "14"                    },
-  { "gate_2_gray.active",                      "RocksElements.png"     },
-  { "gate_2_gray.active.xpos",                 "5"                     },
-  { "gate_2_gray.active.ypos",                 "2"                     },
-  { "gate_2_gray.active.frames",               "1"                     },
-  { "gate_3_gray",                             "RocksElements.png"     },
-  { "gate_3_gray.xpos",                                "10"                    },
-  { "gate_3_gray.ypos",                                "2"                     },
-  { "gate_3_gray.frames",                      "1"                     },
-  { "gate_3_gray.EDITOR",                      "RocksElements.png"     },
-  { "gate_3_gray.EDITOR.xpos",                 "10"                    },
-  { "gate_3_gray.EDITOR.ypos",                 "14"                    },
-  { "gate_3_gray.active",                      "RocksElements.png"     },
-  { "gate_3_gray.active.xpos",                 "6"                     },
-  { "gate_3_gray.active.ypos",                 "2"                     },
-  { "gate_3_gray.active.frames",               "1"                     },
-  { "gate_4_gray",                             "RocksElements.png"     },
-  { "gate_4_gray.xpos",                                "11"                    },
-  { "gate_4_gray.ypos",                                "2"                     },
-  { "gate_4_gray.frames",                      "1"                     },
-  { "gate_4_gray.EDITOR",                      "RocksElements.png"     },
-  { "gate_4_gray.EDITOR.xpos",                 "11"                    },
-  { "gate_4_gray.EDITOR.ypos",                 "14"                    },
-  { "gate_4_gray.active",                      "RocksElements.png"     },
-  { "gate_4_gray.active.xpos",                 "7"                     },
-  { "gate_4_gray.active.ypos",                 "2"                     },
-  { "gate_4_gray.active.frames",               "1"                     },
-
-  { "game_of_life",                            "RocksElements.png"     },
-  { "game_of_life.xpos",                       "8"                     },
-  { "game_of_life.ypos",                       "1"                     },
-  { "game_of_life.frames",                     "1"                     },
-
-  { "biomaze",                                 "RocksElements.png"     },
-  { "biomaze.xpos",                            "9"                     },
-  { "biomaze.ypos",                            "1"                     },
-  { "biomaze.frames",                          "1"                     },
-
-  { "pacman",                                  "RocksElements.png"     },
-  { "pacman.xpos",                             "8"                     },
-  { "pacman.ypos",                             "5"                     },
-  { "pacman.frames",                           "1"                     },
-  { "pacman.right",                            "RocksElements.png"     },
-  { "pacman.right.xpos",                       "8"                     },
-  { "pacman.right.ypos",                       "5"                     },
-  { "pacman.right.frames",                     "2"                     },
-  { "pacman.right.delay",                      "4"                     },
-  { "pacman.right.offset",                     "128"                   },
-  { "pacman.up",                               "RocksElements.png"     },
-  { "pacman.up.xpos",                          "9"                     },
-  { "pacman.up.ypos",                          "5"                     },
-  { "pacman.up.frames",                                "2"                     },
-  { "pacman.up.delay",                         "4"                     },
-  { "pacman.up.offset",                                "128"                   },
-  { "pacman.left",                             "RocksElements.png"     },
-  { "pacman.left.xpos",                                "10"                    },
-  { "pacman.left.ypos",                                "5"                     },
-  { "pacman.left.frames",                      "2"                     },
-  { "pacman.left.delay",                       "4"                     },
-  { "pacman.left.offset",                      "128"                   },
-  { "pacman.down",                             "RocksElements.png"     },
-  { "pacman.down.xpos",                                "11"                    },
-  { "pacman.down.ypos",                                "5"                     },
-  { "pacman.down.frames",                      "2"                     },
-  { "pacman.down.delay",                       "4"                     },
-  { "pacman.down.offset",                      "128"                   },
-  { "pacman.turning_from_right",               "RocksElements.png"     },
-  { "pacman.turning_from_right.xpos",          "12"                    },
-  { "pacman.turning_from_right.ypos",          "5"                     },
-  { "pacman.turning_from_right.frames",                "1"                     },
-  { "pacman.turning_from_up",                  "RocksElements.png"     },
-  { "pacman.turning_from_up.xpos",             "13"                    },
-  { "pacman.turning_from_up.ypos",             "5"                     },
-  { "pacman.turning_from_up.frames",           "1"                     },
-  { "pacman.turning_from_left",                        "RocksElements.png"     },
-  { "pacman.turning_from_left.xpos",           "14"                    },
-  { "pacman.turning_from_left.ypos",           "5"                     },
-  { "pacman.turning_from_left.frames",         "1"                     },
-  { "pacman.turning_from_down",                        "RocksElements.png"     },
-  { "pacman.turning_from_down.xpos",           "15"                    },
-  { "pacman.turning_from_down.ypos",           "5"                     },
-  { "pacman.turning_from_down.frames",         "1"                     },
-
-  { "lamp",                                    "RocksElements.png"     },
-  { "lamp.xpos",                               "0"                     },
-  { "lamp.ypos",                               "7"                     },
-  { "lamp.frames",                             "1"                     },
-  { "lamp.active",                             "RocksElements.png"     },
-  { "lamp.active.xpos",                                "1"                     },
-  { "lamp.active.ypos",                                "7"                     },
-  { "lamp.active.frames",                      "1"                     },
-
-  { "time_orb_full",                           "RocksElements.png"     },
-  { "time_orb_full.xpos",                      "2"                     },
-  { "time_orb_full.ypos",                      "7"                     },
-  { "time_orb_full.frames",                    "1"                     },
-  { "time_orb_empty",                          "RocksElements.png"     },
-  { "time_orb_empty.xpos",                     "3"                     },
-  { "time_orb_empty.ypos",                     "7"                     },
-  { "time_orb_empty.frames",                   "1"                     },
-
-  { "emerald_yellow",                          "RocksElements.png"     },
-  { "emerald_yellow.xpos",                     "10"                    },
-  { "emerald_yellow.ypos",                     "8"                     },
-  { "emerald_yellow.frames",                   "1"                     },
-  { "emerald_yellow.moving",                   "RocksElements.png"     },
-  { "emerald_yellow.moving.xpos",              "10"                    },
-  { "emerald_yellow.moving.ypos",              "8"                     },
-  { "emerald_yellow.moving.frames",            "2"                     },
-  { "emerald_yellow.moving.delay",             "4"                     },
-  { "emerald_yellow.falling",                  "RocksElements.png"     },
-  { "emerald_yellow.falling.xpos",             "10"                    },
-  { "emerald_yellow.falling.ypos",             "8"                     },
-  { "emerald_yellow.falling.frames",           "2"                     },
-  { "emerald_yellow.falling.delay",            "4"                     },
-  { "emerald_yellow.collecting",               "RocksCollect.png"      },
-  { "emerald_yellow.collecting.xpos",          "0"                     },
-  { "emerald_yellow.collecting.ypos",          "9"                     },
-  { "emerald_yellow.collecting.frames",                "7"                     },
-  { "emerald_yellow.collecting.anim_mode",     "linear"                },
-  { "emerald_red",                             "RocksElements.png"     },
-  { "emerald_red.xpos",                                "8"                     },
-  { "emerald_red.ypos",                                "9"                     },
-  { "emerald_red.frames",                      "1"                     },
-  { "emerald_red.moving",                      "RocksElements.png"     },
-  { "emerald_red.moving.xpos",                 "8"                     },
-  { "emerald_red.moving.ypos",                 "9"                     },
-  { "emerald_red.moving.frames",               "2"                     },
-  { "emerald_red.moving.delay",                        "4"                     },
-  { "emerald_red.falling",                     "RocksElements.png"     },
-  { "emerald_red.falling.xpos",                        "8"                     },
-  { "emerald_red.falling.ypos",                        "9"                     },
-  { "emerald_red.falling.frames",              "2"                     },
-  { "emerald_red.falling.delay",               "4"                     },
-  { "emerald_red.collecting",                  "RocksCollect.png"      },
-  { "emerald_red.collecting.xpos",             "0"                     },
-  { "emerald_red.collecting.ypos",             "13"                    },
-  { "emerald_red.collecting.frames",           "7"                     },
-  { "emerald_red.collecting.anim_mode",                "linear"                },
-  { "emerald_purple",                          "RocksElements.png"     },
-  { "emerald_purple.xpos",                     "10"                    },
-  { "emerald_purple.ypos",                     "9"                     },
-  { "emerald_purple.frames",                   "1"                     },
-  { "emerald_purple.moving",                   "RocksElements.png"     },
-  { "emerald_purple.moving.xpos",              "10"                    },
-  { "emerald_purple.moving.ypos",              "9"                     },
-  { "emerald_purple.moving.frames",            "2"                     },
-  { "emerald_purple.moving.delay",             "4"                     },
-  { "emerald_purple.falling",                  "RocksElements.png"     },
-  { "emerald_purple.falling.xpos",             "10"                    },
-  { "emerald_purple.falling.ypos",             "9"                     },
-  { "emerald_purple.falling.frames",           "2"                     },
-  { "emerald_purple.falling.delay",            "4"                     },
-  { "emerald_purple.collecting",               "RocksCollect.png"      },
-  { "emerald_purple.collecting.xpos",          "0"                     },
-  { "emerald_purple.collecting.ypos",          "14"                    },
-  { "emerald_purple.collecting.frames",                "7"                     },
-  { "emerald_purple.collecting.anim_mode",     "linear"                },
-
-  { "wall_emerald_yellow",                     "RocksElements.png"     },
-  { "wall_emerald_yellow.xpos",                        "8"                     },
-  { "wall_emerald_yellow.ypos",                        "8"                     },
-  { "wall_emerald_yellow.frames",              "1"                     },
-  { "wall_emerald_red",                                "RocksElements.png"     },
-  { "wall_emerald_red.xpos",                   "6"                     },
-  { "wall_emerald_red.ypos",                   "8"                     },
-  { "wall_emerald_red.frames",                 "1"                     },
-  { "wall_emerald_purple",                     "RocksElements.png"     },
-  { "wall_emerald_purple.xpos",                        "7"                     },
-  { "wall_emerald_purple.ypos",                        "8"                     },
-  { "wall_emerald_purple.frames",              "1"                     },
-  { "wall_bd_diamond",                         "RocksElements.png"     },
-  { "wall_bd_diamond.xpos",                    "9"                     },
-  { "wall_bd_diamond.ypos",                    "8"                     },
-  { "wall_bd_diamond.frames",                  "1"                     },
-
-  { "expandable_wall",                         "RocksElements.png"     },
-  { "expandable_wall.xpos",                    "11"                    },
-  { "expandable_wall.ypos",                    "10"                    },
-  { "expandable_wall.frames",                  "1"                     },
-  { "expandable_wall_horizontal",              "RocksElements.png"     },
-  { "expandable_wall_horizontal.xpos",         "5"                     },
-  { "expandable_wall_horizontal.ypos",         "9"                     },
-  { "expandable_wall_horizontal.frames",       "1"                     },
-  { "expandable_wall_horizontal.EDITOR",       "RocksElements.png"     },
-  { "expandable_wall_horizontal.EDITOR.xpos",  "13"                    },
-  { "expandable_wall_horizontal.EDITOR.ypos",  "13"                    },
-  { "expandable_wall_vertical",                        "RocksElements.png"     },
-  { "expandable_wall_vertical.xpos",           "6"                     },
-  { "expandable_wall_vertical.ypos",           "9"                     },
-  { "expandable_wall_vertical.frames",         "1"                     },
-  { "expandable_wall_vertical.EDITOR",         "RocksElements.png"     },
-  { "expandable_wall_vertical.EDITOR.xpos",    "14"                    },
-  { "expandable_wall_vertical.EDITOR.ypos",    "13"                    },
-  { "expandable_wall_any",                     "RocksElements.png"     },
-  { "expandable_wall_any.xpos",                        "4"                     },
-  { "expandable_wall_any.ypos",                        "9"                     },
-  { "expandable_wall_any.frames",              "1"                     },
-  { "expandable_wall_any.EDITOR",              "RocksElements.png"     },
-  { "expandable_wall_any.EDITOR.xpos",         "12"                    },
-  { "expandable_wall_any.EDITOR.ypos",         "13"                    },
-
-  { "expandable_steelwall_horizontal",         "RocksDC2.png"          },
-  { "expandable_steelwall_horizontal.xpos",    "6"                     },
-  { "expandable_steelwall_horizontal.ypos",    "2"                     },
-  { "expandable_steelwall_horizontal.frames",  "1"                     },
-  { "expandable_steelwall_horizontal.EDITOR",  "RocksDC2.png"          },
-  { "expandable_steelwall_horizontal.EDITOR.xpos","9"                  },
-  { "expandable_steelwall_horizontal.EDITOR.ypos","2"                  },
-  { "expandable_steelwall_vertical",           "RocksDC2.png"          },
-  { "expandable_steelwall_vertical.xpos",      "6"                     },
-  { "expandable_steelwall_vertical.ypos",      "2"                     },
-  { "expandable_steelwall_vertical.frames",    "1"                     },
-  { "expandable_steelwall_vertical.EDITOR",    "RocksDC2.png"          },
-  { "expandable_steelwall_vertical.EDITOR.xpos","10"                   },
-  { "expandable_steelwall_vertical.EDITOR.ypos","2"                    },
-  { "expandable_steelwall_any",                        "RocksDC2.png"          },
-  { "expandable_steelwall_any.xpos",           "6"                     },
-  { "expandable_steelwall_any.ypos",           "2"                     },
-  { "expandable_steelwall_any.frames",         "1"                     },
-  { "expandable_steelwall_any.EDITOR",         "RocksDC2.png"          },
-  { "expandable_steelwall_any.EDITOR.xpos",    "8"                     },
-  { "expandable_steelwall_any.EDITOR.ypos",    "2"                     },
-
-  { "bd_expandable_wall",                      "RocksElements.png"     },
-  { "bd_expandable_wall.xpos",                 "5"                     },
-  { "bd_expandable_wall.ypos",                 "9"                     },
-  { "bd_expandable_wall.frames",               "1"                     },
-  { "bd_expandable_wall.EDITOR",               "RocksDC.png"           },
-  { "bd_expandable_wall.EDITOR.xpos",          "15"                    },
-  { "bd_expandable_wall.EDITOR.ypos",          "15"                    },
-
-  { "expandable_wall.growing.left",            "RocksElements.png"     },
-  { "expandable_wall.growing.left.xpos",       "8"                     },
-  { "expandable_wall.growing.left.ypos",       "10"                    },
-  { "expandable_wall.growing.left.frames",     "3"                     },
-  { "expandable_wall.growing.left.delay",      "6"                     },
-  { "expandable_wall.growing.left.anim_mode",  "linear"                },
-  { "expandable_wall.growing.right",           "RocksElements.png"     },
-  { "expandable_wall.growing.right.xpos",      "5"                     },
-  { "expandable_wall.growing.right.ypos",      "10"                    },
-  { "expandable_wall.growing.right.frames",    "3"                     },
-  { "expandable_wall.growing.right.delay",     "6"                     },
-  { "expandable_wall.growing.right.anim_mode", "linear"                },
-  { "expandable_wall.growing.up",              "RocksHeroes.png"       },
-  { "expandable_wall.growing.up.xpos",         "3"                     },
-  { "expandable_wall.growing.up.ypos",         "12"                    },
-  { "expandable_wall.growing.up.frames",       "3"                     },
-  { "expandable_wall.growing.up.delay",                "6"                     },
-  { "expandable_wall.growing.up.anim_mode",    "linear"                },
-  { "expandable_wall.growing.down",            "RocksHeroes.png"       },
-  { "expandable_wall.growing.down.xpos",       "0"                     },
-  { "expandable_wall.growing.down.ypos",       "12"                    },
-  { "expandable_wall.growing.down.frames",     "3"                     },
-  { "expandable_wall.growing.down.delay",      "6"                     },
-  { "expandable_wall.growing.down.anim_mode",  "linear"                },
-
-  { "expandable_steelwall.growing.left",       "RocksDC2.png"          },
-  { "expandable_steelwall.growing.left.xpos",  "8"                     },
-  { "expandable_steelwall.growing.left.ypos",  "4"                     },
-  { "expandable_steelwall.growing.left.frames",        "4"                     },
-  { "expandable_steelwall.growing.left.delay", "4"                     },
-  { "expandable_steelwall.growing.left.anim_mode","linear"             },
-  { "expandable_steelwall.growing.right",      "RocksDC2.png"          },
-  { "expandable_steelwall.growing.right.xpos", "12"                    },
-  { "expandable_steelwall.growing.right.ypos", "4"                     },
-  { "expandable_steelwall.growing.right.frames","4"                    },
-  { "expandable_steelwall.growing.right.delay",        "4"                     },
-  { "expandable_steelwall.growing.right.anim_mode","linear"            },
-  { "expandable_steelwall.growing.up",         "RocksDC2.png"          },
-  { "expandable_steelwall.growing.up.xpos",    "8"                     },
-  { "expandable_steelwall.growing.up.ypos",    "5"                     },
-  { "expandable_steelwall.growing.up.frames",  "4"                     },
-  { "expandable_steelwall.growing.up.delay",   "4"                     },
-  { "expandable_steelwall.growing.up.anim_mode","linear"               },
-  { "expandable_steelwall.growing.down",       "RocksDC2.png"          },
-  { "expandable_steelwall.growing.down.xpos",  "12"                    },
-  { "expandable_steelwall.growing.down.ypos",  "5"                     },
-  { "expandable_steelwall.growing.down.frames",        "4"                     },
-  { "expandable_steelwall.growing.down.delay", "4"                     },
-  { "expandable_steelwall.growing.down.anim_mode","linear"             },
-
-  { "black_orb",                               "RocksElements.png"     },
-  { "black_orb.xpos",                          "13"                    },
-  { "black_orb.ypos",                          "9"                     },
-  { "black_orb.frames",                                "1"                     },
-
-  { "speed_pill",                              "RocksElements.png"     },
-  { "speed_pill.xpos",                         "14"                    },
-  { "speed_pill.ypos",                         "9"                     },
-  { "speed_pill.frames",                       "1"                     },
-  { "speed_pill.collecting",                   "RocksCollect.png"      },
-  { "speed_pill.collecting.xpos",              "0"                     },
-  { "speed_pill.collecting.ypos",              "2"                     },
-  { "speed_pill.collecting.frames",            "7"                     },
-  { "speed_pill.collecting.anim_mode",         "linear"                },
-
-  { "dark_yamyam",                             "RocksElements.png"     },
-  { "dark_yamyam.xpos",                                "8"                     },
-  { "dark_yamyam.ypos",                                "11"                    },
-  { "dark_yamyam.frames",                      "4"                     },
-  { "dark_yamyam.anim_mode",                   "pingpong2"             },
-
-  { "dynabomb",                                        "RocksElements.png"     },
-  { "dynabomb.xpos",                           "12"                    },
-  { "dynabomb.ypos",                           "11"                    },
-  { "dynabomb.frames",                         "1"                     },
-  { "dynabomb.active",                         "RocksElements.png"     },
-  { "dynabomb.active.xpos",                    "12"                    },
-  { "dynabomb.active.ypos",                    "11"                    },
-  { "dynabomb.active.frames",                  "4"                     },
-  { "dynabomb.active.delay",                   "6"                     },
-  { "dynabomb.active.anim_mode",               "pingpong"              },
-  { "dynabomb_player_1",                       "RocksElements.png"     },
-  { "dynabomb_player_1.xpos",                  "12"                    },
-  { "dynabomb_player_1.ypos",                  "11"                    },
-  { "dynabomb_player_1.frames",                        "1"                     },
-  { "dynabomb_player_1.active",                        "RocksElements.png"     },
-  { "dynabomb_player_1.active.xpos",           "12"                    },
-  { "dynabomb_player_1.active.ypos",           "11"                    },
-  { "dynabomb_player_1.active.frames",         "4"                     },
-  { "dynabomb_player_1.active.delay",          "6"                     },
-  { "dynabomb_player_1.active.anim_mode",      "pingpong"              },
-  { "dynabomb_player_2",                       "RocksElements.png"     },
-  { "dynabomb_player_2.xpos",                  "12"                    },
-  { "dynabomb_player_2.ypos",                  "11"                    },
-  { "dynabomb_player_2.frames",                        "1"                     },
-  { "dynabomb_player_2.active",                        "RocksElements.png"     },
-  { "dynabomb_player_2.active.xpos",           "12"                    },
-  { "dynabomb_player_2.active.ypos",           "11"                    },
-  { "dynabomb_player_2.active.frames",         "4"                     },
-  { "dynabomb_player_2.active.delay",          "6"                     },
-  { "dynabomb_player_2.active.anim_mode",      "pingpong"              },
-  { "dynabomb_player_3",                       "RocksElements.png"     },
-  { "dynabomb_player_3.xpos",                  "12"                    },
-  { "dynabomb_player_3.ypos",                  "11"                    },
-  { "dynabomb_player_3.frames",                        "1"                     },
-  { "dynabomb_player_3.active",                        "RocksElements.png"     },
-  { "dynabomb_player_3.active.xpos",           "12"                    },
-  { "dynabomb_player_3.active.ypos",           "11"                    },
-  { "dynabomb_player_3.active.frames",         "4"                     },
-  { "dynabomb_player_3.active.delay",          "6"                     },
-  { "dynabomb_player_3.active.anim_mode",      "pingpong"              },
-  { "dynabomb_player_4",                       "RocksElements.png"     },
-  { "dynabomb_player_4.xpos",                  "12"                    },
-  { "dynabomb_player_4.ypos",                  "11"                    },
-  { "dynabomb_player_4.frames",                        "1"                     },
-  { "dynabomb_player_4.active",                        "RocksElements.png"     },
-  { "dynabomb_player_4.active.xpos",           "12"                    },
-  { "dynabomb_player_4.active.ypos",           "11"                    },
-  { "dynabomb_player_4.active.frames",         "4"                     },
-  { "dynabomb_player_4.active.delay",          "6"                     },
-  { "dynabomb_player_4.active.anim_mode",      "pingpong"              },
-  { "dynabomb_increase_number",                        "RocksElements.png"     },
-  { "dynabomb_increase_number.xpos",           "12"                    },
-  { "dynabomb_increase_number.ypos",           "11"                    },
-  { "dynabomb_increase_number.frames",         "1"                     },
-  { "dynabomb_increase_number.collecting",     "RocksCollect.png"      },
-  { "dynabomb_increase_number.collecting.xpos",        "0"                     },
-  { "dynabomb_increase_number.collecting.ypos",        "10"                    },
-  { "dynabomb_increase_number.collecting.frames", "7"                  },
-  { "dynabomb_increase_number.collecting.anim_mode", "linear"          },
-  { "dynabomb_increase_size",                  "RocksElements.png"     },
-  { "dynabomb_increase_size.xpos",             "15"                    },
-  { "dynabomb_increase_size.ypos",             "11"                    },
-  { "dynabomb_increase_size.frames",           "1"                     },
-  { "dynabomb_increase_size.collecting",       "RocksCollect.png"      },
-  { "dynabomb_increase_size.collecting.xpos",  "0"                     },
-  { "dynabomb_increase_size.collecting.ypos",  "11"                    },
-  { "dynabomb_increase_size.collecting.frames",        "7"                     },
-  { "dynabomb_increase_size.collecting.anim_mode", "linear"            },
-  { "dynabomb_increase_power",                 "RocksElements.png"     },
-  { "dynabomb_increase_power.xpos",            "12"                    },
-  { "dynabomb_increase_power.ypos",            "9"                     },
-  { "dynabomb_increase_power.frames",          "1"                     },
-  { "dynabomb_increase_power.collecting",      "RocksCollect.png"      },
-  { "dynabomb_increase_power.collecting.xpos", "0"                     },
-  { "dynabomb_increase_power.collecting.ypos", "12"                    },
-  { "dynabomb_increase_power.collecting.frames", "7"                   },
-  { "dynabomb_increase_power.collecting.anim_mode", "linear"           },
-
-  { "pig",                                     "RocksHeroes.png"       },
-  { "pig.xpos",                                        "8"                     },
-  { "pig.ypos",                                        "0"                     },
-  { "pig.frames",                              "1"                     },
-  { "pig.down",                                        "RocksHeroes.png"       },
-  { "pig.down.xpos",                           "8"                     },
-  { "pig.down.ypos",                           "0"                     },
-  { "pig.down.frames",                         "1"                     },
-  { "pig.up",                                  "RocksHeroes.png"       },
-  { "pig.up.xpos",                             "12"                    },
-  { "pig.up.ypos",                             "0"                     },
-  { "pig.up.frames",                           "1"                     },
-  { "pig.left",                                        "RocksHeroes.png"       },
-  { "pig.left.xpos",                           "8"                     },
-  { "pig.left.ypos",                           "1"                     },
-  { "pig.left.frames",                         "1"                     },
-  { "pig.right",                               "RocksHeroes.png"       },
-  { "pig.right.xpos",                          "12"                    },
-  { "pig.right.ypos",                          "1"                     },
-  { "pig.right.frames",                                "1"                     },
-  { "pig.moving.down",                         "RocksHeroes.png"       },
-  { "pig.moving.down.xpos",                    "8"                     },
-  { "pig.moving.down.ypos",                    "0"                     },
-  { "pig.moving.down.frames",                  "4"                     },
-  { "pig.moving.down.delay",                   "2"                     },
-  { "pig.moving.up",                           "RocksHeroes.png"       },
-  { "pig.moving.up.xpos",                      "12"                    },
-  { "pig.moving.up.ypos",                      "0"                     },
-  { "pig.moving.up.frames",                    "4"                     },
-  { "pig.moving.up.delay",                     "2"                     },
-  { "pig.moving.left",                         "RocksHeroes.png"       },
-  { "pig.moving.left.xpos",                    "8"                     },
-  { "pig.moving.left.ypos",                    "1"                     },
-  { "pig.moving.left.frames",                  "4"                     },
-  { "pig.moving.left.delay",                   "2"                     },
-  { "pig.moving.right",                                "RocksHeroes.png"       },
-  { "pig.moving.right.xpos",                   "12"                    },
-  { "pig.moving.right.ypos",                   "1"                     },
-  { "pig.moving.right.frames",                 "4"                     },
-  { "pig.moving.right.delay",                  "2"                     },
-  { "pig.digging.down",                                "RocksHeroes.png"       },
-  { "pig.digging.down.xpos",                   "8"                     },
-  { "pig.digging.down.ypos",                   "0"                     },
-  { "pig.digging.down.frames",                 "4"                     },
-  { "pig.digging.down.delay",                  "2"                     },
-  { "pig.digging.up",                          "RocksHeroes.png"       },
-  { "pig.digging.up.xpos",                     "12"                    },
-  { "pig.digging.up.ypos",                     "0"                     },
-  { "pig.digging.up.frames",                   "4"                     },
-  { "pig.digging.up.delay",                    "2"                     },
-  { "pig.digging.left",                                "RocksHeroes.png"       },
-  { "pig.digging.left.xpos",                   "8"                     },
-  { "pig.digging.left.ypos",                   "1"                     },
-  { "pig.digging.left.frames",                 "4"                     },
-  { "pig.digging.left.delay",                  "2"                     },
-  { "pig.digging.right",                       "RocksHeroes.png"       },
-  { "pig.digging.right.xpos",                  "12"                    },
-  { "pig.digging.right.ypos",                  "1"                     },
-  { "pig.digging.right.frames",                        "4"                     },
-  { "pig.digging.right.delay",                 "2"                     },
-
-  { "dragon",                                  "RocksHeroes.png"       },
-  { "dragon.xpos",                             "8"                     },
-  { "dragon.ypos",                             "2"                     },
-  { "dragon.frames",                           "1"                     },
-  { "dragon.down",                             "RocksHeroes.png"       },
-  { "dragon.down.xpos",                                "8"                     },
-  { "dragon.down.ypos",                                "2"                     },
-  { "dragon.down.frames",                      "1"                     },
-  { "dragon.up",                               "RocksHeroes.png"       },
-  { "dragon.up.xpos",                          "12"                    },
-  { "dragon.up.ypos",                          "2"                     },
-  { "dragon.up.frames",                                "1"                     },
-  { "dragon.left",                             "RocksHeroes.png"       },
-  { "dragon.left.xpos",                                "8"                     },
-  { "dragon.left.ypos",                                "3"                     },
-  { "dragon.left.frames",                      "1"                     },
-  { "dragon.right",                            "RocksHeroes.png"       },
-  { "dragon.right.xpos",                       "12"                    },
-  { "dragon.right.ypos",                       "3"                     },
-  { "dragon.right.frames",                     "1"                     },
-  { "dragon.moving.down",                      "RocksHeroes.png"       },
-  { "dragon.moving.down.xpos",                 "8"                     },
-  { "dragon.moving.down.ypos",                 "2"                     },
-  { "dragon.moving.down.frames",               "4"                     },
-  { "dragon.moving.down.delay",                        "2"                     },
-  { "dragon.moving.up",                                "RocksHeroes.png"       },
-  { "dragon.moving.up.xpos",                   "12"                    },
-  { "dragon.moving.up.ypos",                   "2"                     },
-  { "dragon.moving.up.frames",                 "4"                     },
-  { "dragon.moving.up.delay",                  "2"                     },
-  { "dragon.moving.left",                      "RocksHeroes.png"       },
-  { "dragon.moving.left.xpos",                 "8"                     },
-  { "dragon.moving.left.ypos",                 "3"                     },
-  { "dragon.moving.left.frames",               "4"                     },
-  { "dragon.moving.left.delay",                        "2"                     },
-  { "dragon.moving.right",                     "RocksHeroes.png"       },
-  { "dragon.moving.right.xpos",                        "12"                    },
-  { "dragon.moving.right.ypos",                        "3"                     },
-  { "dragon.moving.right.frames",              "4"                     },
-  { "dragon.moving.right.delay",               "2"                     },
-  { "dragon.attacking.down",                   "RocksHeroes.png"       },
-  { "dragon.attacking.down.xpos",              "8"                     },
-  { "dragon.attacking.down.ypos",              "2"                     },
-  { "dragon.attacking.down.frames",            "1"                     },
-  { "dragon.attacking.up",                     "RocksHeroes.png"       },
-  { "dragon.attacking.up.xpos",                        "12"                    },
-  { "dragon.attacking.up.ypos",                        "2"                     },
-  { "dragon.attacking.up.frames",              "1"                     },
-  { "dragon.attacking.left",                   "RocksHeroes.png"       },
-  { "dragon.attacking.left.xpos",              "8"                     },
-  { "dragon.attacking.left.ypos",              "3"                     },
-  { "dragon.attacking.left.frames",            "1"                     },
-  { "dragon.attacking.right",                  "RocksHeroes.png"       },
-  { "dragon.attacking.right.xpos",             "12"                    },
-  { "dragon.attacking.right.ypos",             "3"                     },
-  { "dragon.attacking.right.frames",           "1"                     },
-
-  { "mole",                                    "RocksHeroes.png"       },
-  { "mole.xpos",                               "8"                     },
-  { "mole.ypos",                               "4"                     },
-  { "mole.frames",                             "1"                     },
-  { "mole.down",                               "RocksHeroes.png"       },
-  { "mole.down.xpos",                          "8"                     },
-  { "mole.down.ypos",                          "4"                     },
-  { "mole.down.frames",                                "1"                     },
-  { "mole.up",                                 "RocksHeroes.png"       },
-  { "mole.up.xpos",                            "12"                    },
-  { "mole.up.ypos",                            "4"                     },
-  { "mole.up.frames",                          "1"                     },
-  { "mole.left",                               "RocksHeroes.png"       },
-  { "mole.left.xpos",                          "8"                     },
-  { "mole.left.ypos",                          "5"                     },
-  { "mole.left.frames",                                "1"                     },
-  { "mole.right",                              "RocksHeroes.png"       },
-  { "mole.right.xpos",                         "12"                    },
-  { "mole.right.ypos",                         "5"                     },
-  { "mole.right.frames",                       "1"                     },
-  { "mole.moving.down",                                "RocksHeroes.png"       },
-  { "mole.moving.down.xpos",                   "8"                     },
-  { "mole.moving.down.ypos",                   "4"                     },
-  { "mole.moving.down.frames",                 "4"                     },
-  { "mole.moving.down.delay",                  "2"                     },
-  { "mole.moving.up",                          "RocksHeroes.png"       },
-  { "mole.moving.up.xpos",                     "12"                    },
-  { "mole.moving.up.ypos",                     "4"                     },
-  { "mole.moving.up.frames",                   "4"                     },
-  { "mole.moving.up.delay",                    "2"                     },
-  { "mole.moving.left",                                "RocksHeroes.png"       },
-  { "mole.moving.left.xpos",                   "8"                     },
-  { "mole.moving.left.ypos",                   "5"                     },
-  { "mole.moving.left.frames",                 "4"                     },
-  { "mole.moving.left.delay",                  "2"                     },
-  { "mole.moving.right",                       "RocksHeroes.png"       },
-  { "mole.moving.right.xpos",                  "12"                    },
-  { "mole.moving.right.ypos",                  "5"                     },
-  { "mole.moving.right.frames",                        "4"                     },
-  { "mole.moving.right.delay",                 "2"                     },
-  { "mole.digging.down",                       "RocksHeroes.png"       },
-  { "mole.digging.down.xpos",                  "8"                     },
-  { "mole.digging.down.ypos",                  "4"                     },
-  { "mole.digging.down.frames",                        "4"                     },
-  { "mole.digging.down.delay",                 "2"                     },
-  { "mole.digging.up",                         "RocksHeroes.png"       },
-  { "mole.digging.up.xpos",                    "12"                    },
-  { "mole.digging.up.ypos",                    "4"                     },
-  { "mole.digging.up.frames",                  "4"                     },
-  { "mole.digging.up.delay",                   "2"                     },
-  { "mole.digging.left",                       "RocksHeroes.png"       },
-  { "mole.digging.left.xpos",                  "8"                     },
-  { "mole.digging.left.ypos",                  "5"                     },
-  { "mole.digging.left.frames",                        "4"                     },
-  { "mole.digging.left.delay",                 "2"                     },
-  { "mole.digging.right",                      "RocksHeroes.png"       },
-  { "mole.digging.right.xpos",                 "12"                    },
-  { "mole.digging.right.ypos",                 "5"                     },
-  { "mole.digging.right.frames",               "4"                     },
-  { "mole.digging.right.delay",                        "2"                     },
-
-  { "penguin",                                 "RocksHeroes.png"       },
-  { "penguin.xpos",                            "8"                     },
-  { "penguin.ypos",                            "6"                     },
-  { "penguin.frames",                          "1"                     },
-  { "penguin.down",                            "RocksHeroes.png"       },
-  { "penguin.down.xpos",                       "8"                     },
-  { "penguin.down.ypos",                       "6"                     },
-  { "penguin.down.frames",                     "1"                     },
-  { "penguin.up",                              "RocksHeroes.png"       },
-  { "penguin.up.xpos",                         "12"                    },
-  { "penguin.up.ypos",                         "6"                     },
-  { "penguin.up.frames",                       "1"                     },
-  { "penguin.left",                            "RocksHeroes.png"       },
-  { "penguin.left.xpos",                       "8"                     },
-  { "penguin.left.ypos",                       "7"                     },
-  { "penguin.left.frames",                     "1"                     },
-  { "penguin.right",                           "RocksHeroes.png"       },
-  { "penguin.right.xpos",                      "12"                    },
-  { "penguin.right.ypos",                      "7"                     },
-  { "penguin.right.frames",                    "1"                     },
-  { "penguin.moving.down",                     "RocksHeroes.png"       },
-  { "penguin.moving.down.xpos",                        "8"                     },
-  { "penguin.moving.down.ypos",                        "6"                     },
-  { "penguin.moving.down.frames",              "4"                     },
-  { "penguin.moving.down.delay",               "2"                     },
-  { "penguin.moving.up",                       "RocksHeroes.png"       },
-  { "penguin.moving.up.xpos",                  "12"                    },
-  { "penguin.moving.up.ypos",                  "6"                     },
-  { "penguin.moving.up.frames",                        "4"                     },
-  { "penguin.moving.up.delay",                 "2"                     },
-  { "penguin.moving.left",                     "RocksHeroes.png"       },
-  { "penguin.moving.left.xpos",                        "8"                     },
-  { "penguin.moving.left.ypos",                        "7"                     },
-  { "penguin.moving.left.frames",              "4"                     },
-  { "penguin.moving.left.delay",               "2"                     },
-  { "penguin.moving.right",                    "RocksHeroes.png"       },
-  { "penguin.moving.right.xpos",               "12"                    },
-  { "penguin.moving.right.ypos",               "7"                     },
-  { "penguin.moving.right.frames",             "4"                     },
-  { "penguin.moving.right.delay",              "2"                     },
-
-  { "satellite",                               "RocksHeroes.png"       },
-  { "satellite.xpos",                          "8"                     },
-  { "satellite.ypos",                          "9"                     },
-  { "satellite.frames",                                "8"                     },
-  { "satellite.delay",                         "2"                     },
-  { "satellite.global_sync",                   "true"                  },
-
-  { "flames_1_left",                           "RocksHeroes.png"       },
-  { "flames_1_left.xpos",                      "8"                     },
-  { "flames_1_left.ypos",                      "12"                    },
-  { "flames_1_left.frames",                    "2"                     },
-  { "flames_1_left.offset",                    "96"                    },
-  { "flames_2_left",                           "RocksHeroes.png"       },
-  { "flames_2_left.xpos",                      "9"                     },
-  { "flames_2_left.ypos",                      "12"                    },
-  { "flames_2_left.frames",                    "2"                     },
-  { "flames_2_left.offset",                    "96"                    },
-  { "flames_3_left",                           "RocksHeroes.png"       },
-  { "flames_3_left.xpos",                      "10"                    },
-  { "flames_3_left.ypos",                      "12"                    },
-  { "flames_3_left.frames",                    "2"                     },
-  { "flames_3_left.offset",                    "96"                    },
-
-  { "flames_1_right",                          "RocksHeroes.png"       },
-  { "flames_1_right.xpos",                     "8"                     },
-  { "flames_1_right.ypos",                     "13"                    },
-  { "flames_1_right.frames",                   "2"                     },
-  { "flames_1_right.offset",                   "96"                    },
-  { "flames_2_right",                          "RocksHeroes.png"       },
-  { "flames_2_right.xpos",                     "9"                     },
-  { "flames_2_right.ypos",                     "13"                    },
-  { "flames_2_right.frames",                   "2"                     },
-  { "flames_2_right.offset",                   "96"                    },
-  { "flames_3_right",                          "RocksHeroes.png"       },
-  { "flames_3_right.xpos",                     "10"                    },
-  { "flames_3_right.ypos",                     "13"                    },
-  { "flames_3_right.frames",                   "2"                     },
-  { "flames_3_right.offset",                   "96"                    },
-
-  { "flames_1_up",                             "RocksHeroes.png"       },
-  { "flames_1_up.xpos",                                "8"                     },
-  { "flames_1_up.ypos",                                "14"                    },
-  { "flames_1_up.frames",                      "2"                     },
-  { "flames_1_up.offset",                      "96"                    },
-  { "flames_2_up",                             "RocksHeroes.png"       },
-  { "flames_2_up.xpos",                                "9"                     },
-  { "flames_2_up.ypos",                                "14"                    },
-  { "flames_2_up.frames",                      "2"                     },
-  { "flames_2_up.offset",                      "96"                    },
-  { "flames_3_up",                             "RocksHeroes.png"       },
-  { "flames_3_up.xpos",                                "10"                    },
-  { "flames_3_up.ypos",                                "14"                    },
-  { "flames_3_up.frames",                      "2"                     },
-  { "flames_3_up.offset",                      "96"                    },
-
-  { "flames_1_down",                           "RocksHeroes.png"       },
-  { "flames_1_down.xpos",                      "8"                     },
-  { "flames_1_down.ypos",                      "15"                    },
-  { "flames_1_down.frames",                    "2"                     },
-  { "flames_1_down.offset",                    "96"                    },
-  { "flames_2_down",                           "RocksHeroes.png"       },
-  { "flames_2_down.xpos",                      "9"                     },
-  { "flames_2_down.ypos",                      "15"                    },
-  { "flames_2_down.frames",                    "2"                     },
-  { "flames_2_down.offset",                    "96"                    },
-  { "flames_3_down",                           "RocksHeroes.png"       },
-  { "flames_3_down.xpos",                      "10"                    },
-  { "flames_3_down.ypos",                      "15"                    },
-  { "flames_3_down.frames",                    "2"                     },
-  { "flames_3_down.offset",                    "96"                    },
-
-  { "stoneblock",                              "RocksElements.png"     },
-  { "stoneblock.xpos",                         "10"                    },
-  { "stoneblock.ypos",                         "1"                     },
-  { "stoneblock.frames",                       "1"                     },
+  { "key_1",                                           "RocksElements.png"             },
+  { "key_1.xpos",                                      "4"                             },
+  { "key_1.ypos",                                      "1"                             },
+  { "key_1.frames",                                    "1"                             },
+  { "key_1.collecting",                                        "RocksCollect.png"              },
+  { "key_1.collecting.xpos",                           "0"                             },
+  { "key_1.collecting.ypos",                           "3"                             },
+  { "key_1.collecting.frames",                         "7"                             },
+  { "key_1.collecting.anim_mode",                      "linear"                        },
+  { "key_2",                                           "RocksElements.png"             },
+  { "key_2.xpos",                                      "5"                             },
+  { "key_2.ypos",                                      "1"                             },
+  { "key_2.frames",                                    "1"                             },
+  { "key_2.collecting",                                        "RocksCollect.png"              },
+  { "key_2.collecting.xpos",                           "0"                             },
+  { "key_2.collecting.ypos",                           "4"                             },
+  { "key_2.collecting.frames",                         "7"                             },
+  { "key_2.collecting.anim_mode",                      "linear"                        },
+  { "key_3",                                           "RocksElements.png"             },
+  { "key_3.xpos",                                      "6"                             },
+  { "key_3.ypos",                                      "1"                             },
+  { "key_3.frames",                                    "1"                             },
+  { "key_3.collecting",                                        "RocksCollect.png"              },
+  { "key_3.collecting.xpos",                           "0"                             },
+  { "key_3.collecting.ypos",                           "5"                             },
+  { "key_3.collecting.frames",                         "7"                             },
+  { "key_3.collecting.anim_mode",                      "linear"                        },
+  { "key_4",                                           "RocksElements.png"             },
+  { "key_4.xpos",                                      "7"                             },
+  { "key_4.ypos",                                      "1"                             },
+  { "key_4.frames",                                    "1"                             },
+  { "key_4.collecting",                                        "RocksCollect.png"              },
+  { "key_4.collecting.xpos",                           "0"                             },
+  { "key_4.collecting.ypos",                           "6"                             },
+  { "key_4.collecting.frames",                         "7"                             },
+  { "key_4.collecting.anim_mode",                      "linear"                        },
+
+  { "gate_1",                                          "RocksElements.png"             },
+  { "gate_1.xpos",                                     "4"                             },
+  { "gate_1.ypos",                                     "2"                             },
+  { "gate_1.frames",                                   "1"                             },
+  { "gate_2",                                          "RocksElements.png"             },
+  { "gate_2.xpos",                                     "5"                             },
+  { "gate_2.ypos",                                     "2"                             },
+  { "gate_2.frames",                                   "1"                             },
+  { "gate_3",                                          "RocksElements.png"             },
+  { "gate_3.xpos",                                     "6"                             },
+  { "gate_3.ypos",                                     "2"                             },
+  { "gate_3.frames",                                   "1"                             },
+  { "gate_4",                                          "RocksElements.png"             },
+  { "gate_4.xpos",                                     "7"                             },
+  { "gate_4.ypos",                                     "2"                             },
+  { "gate_4.frames",                                   "1"                             },
+  { "gate_1_gray",                                     "RocksElements.png"             },
+  { "gate_1_gray.xpos",                                        "8"                             },
+  { "gate_1_gray.ypos",                                        "2"                             },
+  { "gate_1_gray.frames",                              "1"                             },
+  { "gate_1_gray.EDITOR",                              "RocksElements.png"             },
+  { "gate_1_gray.EDITOR.xpos",                         "8"                             },
+  { "gate_1_gray.EDITOR.ypos",                         "14"                            },
+  { "gate_1_gray.active",                              "RocksElements.png"             },
+  { "gate_1_gray.active.xpos",                         "4"                             },
+  { "gate_1_gray.active.ypos",                         "2"                             },
+  { "gate_1_gray.active.frames",                       "1"                             },
+  { "gate_2_gray",                                     "RocksElements.png"             },
+  { "gate_2_gray.xpos",                                        "9"                             },
+  { "gate_2_gray.ypos",                                        "2"                             },
+  { "gate_2_gray.frames",                              "1"                             },
+  { "gate_2_gray.EDITOR",                              "RocksElements.png"             },
+  { "gate_2_gray.EDITOR.xpos",                         "9"                             },
+  { "gate_2_gray.EDITOR.ypos",                         "14"                            },
+  { "gate_2_gray.active",                              "RocksElements.png"             },
+  { "gate_2_gray.active.xpos",                         "5"                             },
+  { "gate_2_gray.active.ypos",                         "2"                             },
+  { "gate_2_gray.active.frames",                       "1"                             },
+  { "gate_3_gray",                                     "RocksElements.png"             },
+  { "gate_3_gray.xpos",                                        "10"                            },
+  { "gate_3_gray.ypos",                                        "2"                             },
+  { "gate_3_gray.frames",                              "1"                             },
+  { "gate_3_gray.EDITOR",                              "RocksElements.png"             },
+  { "gate_3_gray.EDITOR.xpos",                         "10"                            },
+  { "gate_3_gray.EDITOR.ypos",                         "14"                            },
+  { "gate_3_gray.active",                              "RocksElements.png"             },
+  { "gate_3_gray.active.xpos",                         "6"                             },
+  { "gate_3_gray.active.ypos",                         "2"                             },
+  { "gate_3_gray.active.frames",                       "1"                             },
+  { "gate_4_gray",                                     "RocksElements.png"             },
+  { "gate_4_gray.xpos",                                        "11"                            },
+  { "gate_4_gray.ypos",                                        "2"                             },
+  { "gate_4_gray.frames",                              "1"                             },
+  { "gate_4_gray.EDITOR",                              "RocksElements.png"             },
+  { "gate_4_gray.EDITOR.xpos",                         "11"                            },
+  { "gate_4_gray.EDITOR.ypos",                         "14"                            },
+  { "gate_4_gray.active",                              "RocksElements.png"             },
+  { "gate_4_gray.active.xpos",                         "7"                             },
+  { "gate_4_gray.active.ypos",                         "2"                             },
+  { "gate_4_gray.active.frames",                       "1"                             },
+
+  { "game_of_life",                                    "RocksElements.png"             },
+  { "game_of_life.xpos",                               "8"                             },
+  { "game_of_life.ypos",                               "1"                             },
+  { "game_of_life.frames",                             "1"                             },
+
+  { "biomaze",                                         "RocksElements.png"             },
+  { "biomaze.xpos",                                    "9"                             },
+  { "biomaze.ypos",                                    "1"                             },
+  { "biomaze.frames",                                  "1"                             },
+
+  { "pacman",                                          "RocksElements.png"             },
+  { "pacman.xpos",                                     "8"                             },
+  { "pacman.ypos",                                     "5"                             },
+  { "pacman.frames",                                   "1"                             },
+  { "pacman.right",                                    "RocksElements.png"             },
+  { "pacman.right.xpos",                               "8"                             },
+  { "pacman.right.ypos",                               "5"                             },
+  { "pacman.right.frames",                             "2"                             },
+  { "pacman.right.delay",                              "4"                             },
+  { "pacman.right.offset",                             "128"                           },
+  { "pacman.up",                                       "RocksElements.png"             },
+  { "pacman.up.xpos",                                  "9"                             },
+  { "pacman.up.ypos",                                  "5"                             },
+  { "pacman.up.frames",                                        "2"                             },
+  { "pacman.up.delay",                                 "4"                             },
+  { "pacman.up.offset",                                        "128"                           },
+  { "pacman.left",                                     "RocksElements.png"             },
+  { "pacman.left.xpos",                                        "10"                            },
+  { "pacman.left.ypos",                                        "5"                             },
+  { "pacman.left.frames",                              "2"                             },
+  { "pacman.left.delay",                               "4"                             },
+  { "pacman.left.offset",                              "128"                           },
+  { "pacman.down",                                     "RocksElements.png"             },
+  { "pacman.down.xpos",                                        "11"                            },
+  { "pacman.down.ypos",                                        "5"                             },
+  { "pacman.down.frames",                              "2"                             },
+  { "pacman.down.delay",                               "4"                             },
+  { "pacman.down.offset",                              "128"                           },
+  { "pacman.turning_from_right",                       "RocksElements.png"             },
+  { "pacman.turning_from_right.xpos",                  "12"                            },
+  { "pacman.turning_from_right.ypos",                  "5"                             },
+  { "pacman.turning_from_right.frames",                        "1"                             },
+  { "pacman.turning_from_up",                          "RocksElements.png"             },
+  { "pacman.turning_from_up.xpos",                     "13"                            },
+  { "pacman.turning_from_up.ypos",                     "5"                             },
+  { "pacman.turning_from_up.frames",                   "1"                             },
+  { "pacman.turning_from_left",                                "RocksElements.png"             },
+  { "pacman.turning_from_left.xpos",                   "14"                            },
+  { "pacman.turning_from_left.ypos",                   "5"                             },
+  { "pacman.turning_from_left.frames",                 "1"                             },
+  { "pacman.turning_from_down",                                "RocksElements.png"             },
+  { "pacman.turning_from_down.xpos",                   "15"                            },
+  { "pacman.turning_from_down.ypos",                   "5"                             },
+  { "pacman.turning_from_down.frames",                 "1"                             },
+
+  { "lamp",                                            "RocksElements.png"             },
+  { "lamp.xpos",                                       "0"                             },
+  { "lamp.ypos",                                       "7"                             },
+  { "lamp.frames",                                     "1"                             },
+  { "lamp.active",                                     "RocksElements.png"             },
+  { "lamp.active.xpos",                                        "1"                             },
+  { "lamp.active.ypos",                                        "7"                             },
+  { "lamp.active.frames",                              "1"                             },
+
+  { "time_orb_full",                                   "RocksElements.png"             },
+  { "time_orb_full.xpos",                              "2"                             },
+  { "time_orb_full.ypos",                              "7"                             },
+  { "time_orb_full.frames",                            "1"                             },
+  { "time_orb_empty",                                  "RocksElements.png"             },
+  { "time_orb_empty.xpos",                             "3"                             },
+  { "time_orb_empty.ypos",                             "7"                             },
+  { "time_orb_empty.frames",                           "1"                             },
+
+  { "emerald_yellow",                                  "RocksElements.png"             },
+  { "emerald_yellow.xpos",                             "10"                            },
+  { "emerald_yellow.ypos",                             "8"                             },
+  { "emerald_yellow.frames",                           "1"                             },
+  { "emerald_yellow.moving",                           "RocksElements.png"             },
+  { "emerald_yellow.moving.xpos",                      "10"                            },
+  { "emerald_yellow.moving.ypos",                      "8"                             },
+  { "emerald_yellow.moving.frames",                    "2"                             },
+  { "emerald_yellow.moving.delay",                     "4"                             },
+  { "emerald_yellow.falling",                          "RocksElements.png"             },
+  { "emerald_yellow.falling.xpos",                     "10"                            },
+  { "emerald_yellow.falling.ypos",                     "8"                             },
+  { "emerald_yellow.falling.frames",                   "2"                             },
+  { "emerald_yellow.falling.delay",                    "4"                             },
+  { "emerald_yellow.collecting",                       "RocksCollect.png"              },
+  { "emerald_yellow.collecting.xpos",                  "0"                             },
+  { "emerald_yellow.collecting.ypos",                  "9"                             },
+  { "emerald_yellow.collecting.frames",                        "7"                             },
+  { "emerald_yellow.collecting.anim_mode",             "linear"                        },
+  { "emerald_red",                                     "RocksElements.png"             },
+  { "emerald_red.xpos",                                        "8"                             },
+  { "emerald_red.ypos",                                        "9"                             },
+  { "emerald_red.frames",                              "1"                             },
+  { "emerald_red.moving",                              "RocksElements.png"             },
+  { "emerald_red.moving.xpos",                         "8"                             },
+  { "emerald_red.moving.ypos",                         "9"                             },
+  { "emerald_red.moving.frames",                       "2"                             },
+  { "emerald_red.moving.delay",                                "4"                             },
+  { "emerald_red.falling",                             "RocksElements.png"             },
+  { "emerald_red.falling.xpos",                                "8"                             },
+  { "emerald_red.falling.ypos",                                "9"                             },
+  { "emerald_red.falling.frames",                      "2"                             },
+  { "emerald_red.falling.delay",                       "4"                             },
+  { "emerald_red.collecting",                          "RocksCollect.png"              },
+  { "emerald_red.collecting.xpos",                     "0"                             },
+  { "emerald_red.collecting.ypos",                     "13"                            },
+  { "emerald_red.collecting.frames",                   "7"                             },
+  { "emerald_red.collecting.anim_mode",                        "linear"                        },
+  { "emerald_purple",                                  "RocksElements.png"             },
+  { "emerald_purple.xpos",                             "10"                            },
+  { "emerald_purple.ypos",                             "9"                             },
+  { "emerald_purple.frames",                           "1"                             },
+  { "emerald_purple.moving",                           "RocksElements.png"             },
+  { "emerald_purple.moving.xpos",                      "10"                            },
+  { "emerald_purple.moving.ypos",                      "9"                             },
+  { "emerald_purple.moving.frames",                    "2"                             },
+  { "emerald_purple.moving.delay",                     "4"                             },
+  { "emerald_purple.falling",                          "RocksElements.png"             },
+  { "emerald_purple.falling.xpos",                     "10"                            },
+  { "emerald_purple.falling.ypos",                     "9"                             },
+  { "emerald_purple.falling.frames",                   "2"                             },
+  { "emerald_purple.falling.delay",                    "4"                             },
+  { "emerald_purple.collecting",                       "RocksCollect.png"              },
+  { "emerald_purple.collecting.xpos",                  "0"                             },
+  { "emerald_purple.collecting.ypos",                  "14"                            },
+  { "emerald_purple.collecting.frames",                        "7"                             },
+  { "emerald_purple.collecting.anim_mode",             "linear"                        },
+
+  { "wall_emerald_yellow",                             "RocksElements.png"             },
+  { "wall_emerald_yellow.xpos",                                "8"                             },
+  { "wall_emerald_yellow.ypos",                                "8"                             },
+  { "wall_emerald_yellow.frames",                      "1"                             },
+  { "wall_emerald_red",                                        "RocksElements.png"             },
+  { "wall_emerald_red.xpos",                           "6"                             },
+  { "wall_emerald_red.ypos",                           "8"                             },
+  { "wall_emerald_red.frames",                         "1"                             },
+  { "wall_emerald_purple",                             "RocksElements.png"             },
+  { "wall_emerald_purple.xpos",                                "7"                             },
+  { "wall_emerald_purple.ypos",                                "8"                             },
+  { "wall_emerald_purple.frames",                      "1"                             },
+  { "wall_bd_diamond",                                 "RocksElements.png"             },
+  { "wall_bd_diamond.xpos",                            "9"                             },
+  { "wall_bd_diamond.ypos",                            "8"                             },
+  { "wall_bd_diamond.frames",                          "1"                             },
+
+  { "expandable_wall",                                 "RocksElements.png"             },
+  { "expandable_wall.xpos",                            "11"                            },
+  { "expandable_wall.ypos",                            "10"                            },
+  { "expandable_wall.frames",                          "1"                             },
+  { "expandable_wall_horizontal",                      "RocksElements.png"             },
+  { "expandable_wall_horizontal.xpos",                 "5"                             },
+  { "expandable_wall_horizontal.ypos",                 "9"                             },
+  { "expandable_wall_horizontal.frames",               "1"                             },
+  { "expandable_wall_horizontal.EDITOR",               "RocksElements.png"             },
+  { "expandable_wall_horizontal.EDITOR.xpos",          "13"                            },
+  { "expandable_wall_horizontal.EDITOR.ypos",          "13"                            },
+  { "expandable_wall_vertical",                                "RocksElements.png"             },
+  { "expandable_wall_vertical.xpos",                   "6"                             },
+  { "expandable_wall_vertical.ypos",                   "9"                             },
+  { "expandable_wall_vertical.frames",                 "1"                             },
+  { "expandable_wall_vertical.EDITOR",                 "RocksElements.png"             },
+  { "expandable_wall_vertical.EDITOR.xpos",            "14"                            },
+  { "expandable_wall_vertical.EDITOR.ypos",            "13"                            },
+  { "expandable_wall_any",                             "RocksElements.png"             },
+  { "expandable_wall_any.xpos",                                "4"                             },
+  { "expandable_wall_any.ypos",                                "9"                             },
+  { "expandable_wall_any.frames",                      "1"                             },
+  { "expandable_wall_any.EDITOR",                      "RocksElements.png"             },
+  { "expandable_wall_any.EDITOR.xpos",                 "12"                            },
+  { "expandable_wall_any.EDITOR.ypos",                 "13"                            },
+
+  { "expandable_steelwall_horizontal",                 "RocksDC2.png"                  },
+  { "expandable_steelwall_horizontal.xpos",            "6"                             },
+  { "expandable_steelwall_horizontal.ypos",            "2"                             },
+  { "expandable_steelwall_horizontal.frames",          "1"                             },
+  { "expandable_steelwall_horizontal.EDITOR",          "RocksDC2.png"                  },
+  { "expandable_steelwall_horizontal.EDITOR.xpos",     "9"                             },
+  { "expandable_steelwall_horizontal.EDITOR.ypos",     "2"                             },
+  { "expandable_steelwall_vertical",                   "RocksDC2.png"                  },
+  { "expandable_steelwall_vertical.xpos",              "6"                             },
+  { "expandable_steelwall_vertical.ypos",              "2"                             },
+  { "expandable_steelwall_vertical.frames",            "1"                             },
+  { "expandable_steelwall_vertical.EDITOR",            "RocksDC2.png"                  },
+  { "expandable_steelwall_vertical.EDITOR.xpos",       "10"                            },
+  { "expandable_steelwall_vertical.EDITOR.ypos",       "2"                             },
+  { "expandable_steelwall_any",                                "RocksDC2.png"                  },
+  { "expandable_steelwall_any.xpos",                   "6"                             },
+  { "expandable_steelwall_any.ypos",                   "2"                             },
+  { "expandable_steelwall_any.frames",                 "1"                             },
+  { "expandable_steelwall_any.EDITOR",                 "RocksDC2.png"                  },
+  { "expandable_steelwall_any.EDITOR.xpos",            "8"                             },
+  { "expandable_steelwall_any.EDITOR.ypos",            "2"                             },
+
+  { "expandable_wall.growing.left",                    "RocksElements.png"             },
+  { "expandable_wall.growing.left.xpos",               "8"                             },
+  { "expandable_wall.growing.left.ypos",               "10"                            },
+  { "expandable_wall.growing.left.frames",             "3"                             },
+  { "expandable_wall.growing.left.delay",              "6"                             },
+  { "expandable_wall.growing.left.anim_mode",          "linear"                        },
+  { "expandable_wall.growing.right",                   "RocksElements.png"             },
+  { "expandable_wall.growing.right.xpos",              "5"                             },
+  { "expandable_wall.growing.right.ypos",              "10"                            },
+  { "expandable_wall.growing.right.frames",            "3"                             },
+  { "expandable_wall.growing.right.delay",             "6"                             },
+  { "expandable_wall.growing.right.anim_mode",         "linear"                        },
+  { "expandable_wall.growing.up",                      "RocksHeroes.png"               },
+  { "expandable_wall.growing.up.xpos",                 "3"                             },
+  { "expandable_wall.growing.up.ypos",                 "12"                            },
+  { "expandable_wall.growing.up.frames",               "3"                             },
+  { "expandable_wall.growing.up.delay",                        "6"                             },
+  { "expandable_wall.growing.up.anim_mode",            "linear"                        },
+  { "expandable_wall.growing.down",                    "RocksHeroes.png"               },
+  { "expandable_wall.growing.down.xpos",               "0"                             },
+  { "expandable_wall.growing.down.ypos",               "12"                            },
+  { "expandable_wall.growing.down.frames",             "3"                             },
+  { "expandable_wall.growing.down.delay",              "6"                             },
+  { "expandable_wall.growing.down.anim_mode",          "linear"                        },
+
+  { "expandable_steelwall.growing.left",               "RocksDC2.png"                  },
+  { "expandable_steelwall.growing.left.xpos",          "8"                             },
+  { "expandable_steelwall.growing.left.ypos",          "4"                             },
+  { "expandable_steelwall.growing.left.frames",                "4"                             },
+  { "expandable_steelwall.growing.left.delay",         "4"                             },
+  { "expandable_steelwall.growing.left.anim_mode",     "linear"                        },
+  { "expandable_steelwall.growing.right",              "RocksDC2.png"                  },
+  { "expandable_steelwall.growing.right.xpos",         "12"                            },
+  { "expandable_steelwall.growing.right.ypos",         "4"                             },
+  { "expandable_steelwall.growing.right.frames",       "4"                             },
+  { "expandable_steelwall.growing.right.delay",                "4"                             },
+  { "expandable_steelwall.growing.right.anim_mode",    "linear"                        },
+  { "expandable_steelwall.growing.up",                 "RocksDC2.png"                  },
+  { "expandable_steelwall.growing.up.xpos",            "8"                             },
+  { "expandable_steelwall.growing.up.ypos",            "5"                             },
+  { "expandable_steelwall.growing.up.frames",          "4"                             },
+  { "expandable_steelwall.growing.up.delay",           "4"                             },
+  { "expandable_steelwall.growing.up.anim_mode",       "linear"                        },
+  { "expandable_steelwall.growing.down",               "RocksDC2.png"                  },
+  { "expandable_steelwall.growing.down.xpos",          "12"                            },
+  { "expandable_steelwall.growing.down.ypos",          "5"                             },
+  { "expandable_steelwall.growing.down.frames",                "4"                             },
+  { "expandable_steelwall.growing.down.delay",         "4"                             },
+  { "expandable_steelwall.growing.down.anim_mode",     "linear"                        },
+
+  { "black_orb",                                       "RocksElements.png"             },
+  { "black_orb.xpos",                                  "13"                            },
+  { "black_orb.ypos",                                  "9"                             },
+  { "black_orb.frames",                                        "1"                             },
+
+  { "speed_pill",                                      "RocksElements.png"             },
+  { "speed_pill.xpos",                                 "14"                            },
+  { "speed_pill.ypos",                                 "9"                             },
+  { "speed_pill.frames",                               "1"                             },
+  { "speed_pill.collecting",                           "RocksCollect.png"              },
+  { "speed_pill.collecting.xpos",                      "0"                             },
+  { "speed_pill.collecting.ypos",                      "2"                             },
+  { "speed_pill.collecting.frames",                    "7"                             },
+  { "speed_pill.collecting.anim_mode",                 "linear"                        },
+
+  { "dark_yamyam",                                     "RocksElements.png"             },
+  { "dark_yamyam.xpos",                                        "8"                             },
+  { "dark_yamyam.ypos",                                        "11"                            },
+  { "dark_yamyam.frames",                              "4"                             },
+  { "dark_yamyam.anim_mode",                           "pingpong2"                     },
+
+  { "dynabomb",                                                "RocksElements.png"             },
+  { "dynabomb.xpos",                                   "12"                            },
+  { "dynabomb.ypos",                                   "11"                            },
+  { "dynabomb.frames",                                 "1"                             },
+  { "dynabomb.active",                                 "RocksElements.png"             },
+  { "dynabomb.active.xpos",                            "12"                            },
+  { "dynabomb.active.ypos",                            "11"                            },
+  { "dynabomb.active.frames",                          "4"                             },
+  { "dynabomb.active.delay",                           "6"                             },
+  { "dynabomb.active.anim_mode",                       "pingpong"                      },
+  { "dynabomb_player_1",                               "RocksElements.png"             },
+  { "dynabomb_player_1.xpos",                          "12"                            },
+  { "dynabomb_player_1.ypos",                          "11"                            },
+  { "dynabomb_player_1.frames",                                "1"                             },
+  { "dynabomb_player_1.active",                                "RocksElements.png"             },
+  { "dynabomb_player_1.active.xpos",                   "12"                            },
+  { "dynabomb_player_1.active.ypos",                   "11"                            },
+  { "dynabomb_player_1.active.frames",                 "4"                             },
+  { "dynabomb_player_1.active.delay",                  "6"                             },
+  { "dynabomb_player_1.active.anim_mode",              "pingpong"                      },
+  { "dynabomb_player_2",                               "RocksElements.png"             },
+  { "dynabomb_player_2.xpos",                          "12"                            },
+  { "dynabomb_player_2.ypos",                          "11"                            },
+  { "dynabomb_player_2.frames",                                "1"                             },
+  { "dynabomb_player_2.active",                                "RocksElements.png"             },
+  { "dynabomb_player_2.active.xpos",                   "12"                            },
+  { "dynabomb_player_2.active.ypos",                   "11"                            },
+  { "dynabomb_player_2.active.frames",                 "4"                             },
+  { "dynabomb_player_2.active.delay",                  "6"                             },
+  { "dynabomb_player_2.active.anim_mode",              "pingpong"                      },
+  { "dynabomb_player_3",                               "RocksElements.png"             },
+  { "dynabomb_player_3.xpos",                          "12"                            },
+  { "dynabomb_player_3.ypos",                          "11"                            },
+  { "dynabomb_player_3.frames",                                "1"                             },
+  { "dynabomb_player_3.active",                                "RocksElements.png"             },
+  { "dynabomb_player_3.active.xpos",                   "12"                            },
+  { "dynabomb_player_3.active.ypos",                   "11"                            },
+  { "dynabomb_player_3.active.frames",                 "4"                             },
+  { "dynabomb_player_3.active.delay",                  "6"                             },
+  { "dynabomb_player_3.active.anim_mode",              "pingpong"                      },
+  { "dynabomb_player_4",                               "RocksElements.png"             },
+  { "dynabomb_player_4.xpos",                          "12"                            },
+  { "dynabomb_player_4.ypos",                          "11"                            },
+  { "dynabomb_player_4.frames",                                "1"                             },
+  { "dynabomb_player_4.active",                                "RocksElements.png"             },
+  { "dynabomb_player_4.active.xpos",                   "12"                            },
+  { "dynabomb_player_4.active.ypos",                   "11"                            },
+  { "dynabomb_player_4.active.frames",                 "4"                             },
+  { "dynabomb_player_4.active.delay",                  "6"                             },
+  { "dynabomb_player_4.active.anim_mode",              "pingpong"                      },
+  { "dynabomb_increase_number",                                "RocksElements.png"             },
+  { "dynabomb_increase_number.xpos",                   "12"                            },
+  { "dynabomb_increase_number.ypos",                   "11"                            },
+  { "dynabomb_increase_number.frames",                 "1"                             },
+  { "dynabomb_increase_number.collecting",             "RocksCollect.png"              },
+  { "dynabomb_increase_number.collecting.xpos",                "0"                             },
+  { "dynabomb_increase_number.collecting.ypos",                "10"                            },
+  { "dynabomb_increase_number.collecting.frames",      "7"                             },
+  { "dynabomb_increase_number.collecting.anim_mode",   "linear"                        },
+  { "dynabomb_increase_size",                          "RocksElements.png"             },
+  { "dynabomb_increase_size.xpos",                     "15"                            },
+  { "dynabomb_increase_size.ypos",                     "11"                            },
+  { "dynabomb_increase_size.frames",                   "1"                             },
+  { "dynabomb_increase_size.collecting",               "RocksCollect.png"              },
+  { "dynabomb_increase_size.collecting.xpos",          "0"                             },
+  { "dynabomb_increase_size.collecting.ypos",          "11"                            },
+  { "dynabomb_increase_size.collecting.frames",                "7"                             },
+  { "dynabomb_increase_size.collecting.anim_mode",     "linear"                        },
+  { "dynabomb_increase_power",                         "RocksElements.png"             },
+  { "dynabomb_increase_power.xpos",                    "12"                            },
+  { "dynabomb_increase_power.ypos",                    "9"                             },
+  { "dynabomb_increase_power.frames",                  "1"                             },
+  { "dynabomb_increase_power.collecting",              "RocksCollect.png"              },
+  { "dynabomb_increase_power.collecting.xpos",         "0"                             },
+  { "dynabomb_increase_power.collecting.ypos",         "12"                            },
+  { "dynabomb_increase_power.collecting.frames",       "7"                             },
+  { "dynabomb_increase_power.collecting.anim_mode",    "linear"                        },
+
+  { "pig",                                             "RocksHeroes.png"               },
+  { "pig.xpos",                                                "8"                             },
+  { "pig.ypos",                                                "0"                             },
+  { "pig.frames",                                      "1"                             },
+  { "pig.down",                                                "RocksHeroes.png"               },
+  { "pig.down.xpos",                                   "8"                             },
+  { "pig.down.ypos",                                   "0"                             },
+  { "pig.down.frames",                                 "1"                             },
+  { "pig.up",                                          "RocksHeroes.png"               },
+  { "pig.up.xpos",                                     "12"                            },
+  { "pig.up.ypos",                                     "0"                             },
+  { "pig.up.frames",                                   "1"                             },
+  { "pig.left",                                                "RocksHeroes.png"               },
+  { "pig.left.xpos",                                   "8"                             },
+  { "pig.left.ypos",                                   "1"                             },
+  { "pig.left.frames",                                 "1"                             },
+  { "pig.right",                                       "RocksHeroes.png"               },
+  { "pig.right.xpos",                                  "12"                            },
+  { "pig.right.ypos",                                  "1"                             },
+  { "pig.right.frames",                                        "1"                             },
+  { "pig.moving.down",                                 "RocksHeroes.png"               },
+  { "pig.moving.down.xpos",                            "8"                             },
+  { "pig.moving.down.ypos",                            "0"                             },
+  { "pig.moving.down.frames",                          "4"                             },
+  { "pig.moving.down.delay",                           "2"                             },
+  { "pig.moving.up",                                   "RocksHeroes.png"               },
+  { "pig.moving.up.xpos",                              "12"                            },
+  { "pig.moving.up.ypos",                              "0"                             },
+  { "pig.moving.up.frames",                            "4"                             },
+  { "pig.moving.up.delay",                             "2"                             },
+  { "pig.moving.left",                                 "RocksHeroes.png"               },
+  { "pig.moving.left.xpos",                            "8"                             },
+  { "pig.moving.left.ypos",                            "1"                             },
+  { "pig.moving.left.frames",                          "4"                             },
+  { "pig.moving.left.delay",                           "2"                             },
+  { "pig.moving.right",                                        "RocksHeroes.png"               },
+  { "pig.moving.right.xpos",                           "12"                            },
+  { "pig.moving.right.ypos",                           "1"                             },
+  { "pig.moving.right.frames",                         "4"                             },
+  { "pig.moving.right.delay",                          "2"                             },
+  { "pig.digging.down",                                        "RocksHeroes.png"               },
+  { "pig.digging.down.xpos",                           "8"                             },
+  { "pig.digging.down.ypos",                           "0"                             },
+  { "pig.digging.down.frames",                         "4"                             },
+  { "pig.digging.down.delay",                          "2"                             },
+  { "pig.digging.up",                                  "RocksHeroes.png"               },
+  { "pig.digging.up.xpos",                             "12"                            },
+  { "pig.digging.up.ypos",                             "0"                             },
+  { "pig.digging.up.frames",                           "4"                             },
+  { "pig.digging.up.delay",                            "2"                             },
+  { "pig.digging.left",                                        "RocksHeroes.png"               },
+  { "pig.digging.left.xpos",                           "8"                             },
+  { "pig.digging.left.ypos",                           "1"                             },
+  { "pig.digging.left.frames",                         "4"                             },
+  { "pig.digging.left.delay",                          "2"                             },
+  { "pig.digging.right",                               "RocksHeroes.png"               },
+  { "pig.digging.right.xpos",                          "12"                            },
+  { "pig.digging.right.ypos",                          "1"                             },
+  { "pig.digging.right.frames",                                "4"                             },
+  { "pig.digging.right.delay",                         "2"                             },
+
+  { "dragon",                                          "RocksHeroes.png"               },
+  { "dragon.xpos",                                     "8"                             },
+  { "dragon.ypos",                                     "2"                             },
+  { "dragon.frames",                                   "1"                             },
+  { "dragon.down",                                     "RocksHeroes.png"               },
+  { "dragon.down.xpos",                                        "8"                             },
+  { "dragon.down.ypos",                                        "2"                             },
+  { "dragon.down.frames",                              "1"                             },
+  { "dragon.up",                                       "RocksHeroes.png"               },
+  { "dragon.up.xpos",                                  "12"                            },
+  { "dragon.up.ypos",                                  "2"                             },
+  { "dragon.up.frames",                                        "1"                             },
+  { "dragon.left",                                     "RocksHeroes.png"               },
+  { "dragon.left.xpos",                                        "8"                             },
+  { "dragon.left.ypos",                                        "3"                             },
+  { "dragon.left.frames",                              "1"                             },
+  { "dragon.right",                                    "RocksHeroes.png"               },
+  { "dragon.right.xpos",                               "12"                            },
+  { "dragon.right.ypos",                               "3"                             },
+  { "dragon.right.frames",                             "1"                             },
+  { "dragon.moving.down",                              "RocksHeroes.png"               },
+  { "dragon.moving.down.xpos",                         "8"                             },
+  { "dragon.moving.down.ypos",                         "2"                             },
+  { "dragon.moving.down.frames",                       "4"                             },
+  { "dragon.moving.down.delay",                                "2"                             },
+  { "dragon.moving.up",                                        "RocksHeroes.png"               },
+  { "dragon.moving.up.xpos",                           "12"                            },
+  { "dragon.moving.up.ypos",                           "2"                             },
+  { "dragon.moving.up.frames",                         "4"                             },
+  { "dragon.moving.up.delay",                          "2"                             },
+  { "dragon.moving.left",                              "RocksHeroes.png"               },
+  { "dragon.moving.left.xpos",                         "8"                             },
+  { "dragon.moving.left.ypos",                         "3"                             },
+  { "dragon.moving.left.frames",                       "4"                             },
+  { "dragon.moving.left.delay",                                "2"                             },
+  { "dragon.moving.right",                             "RocksHeroes.png"               },
+  { "dragon.moving.right.xpos",                                "12"                            },
+  { "dragon.moving.right.ypos",                                "3"                             },
+  { "dragon.moving.right.frames",                      "4"                             },
+  { "dragon.moving.right.delay",                       "2"                             },
+  { "dragon.attacking.down",                           "RocksHeroes.png"               },
+  { "dragon.attacking.down.xpos",                      "8"                             },
+  { "dragon.attacking.down.ypos",                      "2"                             },
+  { "dragon.attacking.down.frames",                    "1"                             },
+  { "dragon.attacking.up",                             "RocksHeroes.png"               },
+  { "dragon.attacking.up.xpos",                                "12"                            },
+  { "dragon.attacking.up.ypos",                                "2"                             },
+  { "dragon.attacking.up.frames",                      "1"                             },
+  { "dragon.attacking.left",                           "RocksHeroes.png"               },
+  { "dragon.attacking.left.xpos",                      "8"                             },
+  { "dragon.attacking.left.ypos",                      "3"                             },
+  { "dragon.attacking.left.frames",                    "1"                             },
+  { "dragon.attacking.right",                          "RocksHeroes.png"               },
+  { "dragon.attacking.right.xpos",                     "12"                            },
+  { "dragon.attacking.right.ypos",                     "3"                             },
+  { "dragon.attacking.right.frames",                   "1"                             },
+
+  { "mole",                                            "RocksHeroes.png"               },
+  { "mole.xpos",                                       "8"                             },
+  { "mole.ypos",                                       "4"                             },
+  { "mole.frames",                                     "1"                             },
+  { "mole.down",                                       "RocksHeroes.png"               },
+  { "mole.down.xpos",                                  "8"                             },
+  { "mole.down.ypos",                                  "4"                             },
+  { "mole.down.frames",                                        "1"                             },
+  { "mole.up",                                         "RocksHeroes.png"               },
+  { "mole.up.xpos",                                    "12"                            },
+  { "mole.up.ypos",                                    "4"                             },
+  { "mole.up.frames",                                  "1"                             },
+  { "mole.left",                                       "RocksHeroes.png"               },
+  { "mole.left.xpos",                                  "8"                             },
+  { "mole.left.ypos",                                  "5"                             },
+  { "mole.left.frames",                                        "1"                             },
+  { "mole.right",                                      "RocksHeroes.png"               },
+  { "mole.right.xpos",                                 "12"                            },
+  { "mole.right.ypos",                                 "5"                             },
+  { "mole.right.frames",                               "1"                             },
+  { "mole.moving.down",                                        "RocksHeroes.png"               },
+  { "mole.moving.down.xpos",                           "8"                             },
+  { "mole.moving.down.ypos",                           "4"                             },
+  { "mole.moving.down.frames",                         "4"                             },
+  { "mole.moving.down.delay",                          "2"                             },
+  { "mole.moving.up",                                  "RocksHeroes.png"               },
+  { "mole.moving.up.xpos",                             "12"                            },
+  { "mole.moving.up.ypos",                             "4"                             },
+  { "mole.moving.up.frames",                           "4"                             },
+  { "mole.moving.up.delay",                            "2"                             },
+  { "mole.moving.left",                                        "RocksHeroes.png"               },
+  { "mole.moving.left.xpos",                           "8"                             },
+  { "mole.moving.left.ypos",                           "5"                             },
+  { "mole.moving.left.frames",                         "4"                             },
+  { "mole.moving.left.delay",                          "2"                             },
+  { "mole.moving.right",                               "RocksHeroes.png"               },
+  { "mole.moving.right.xpos",                          "12"                            },
+  { "mole.moving.right.ypos",                          "5"                             },
+  { "mole.moving.right.frames",                                "4"                             },
+  { "mole.moving.right.delay",                         "2"                             },
+  { "mole.digging.down",                               "RocksHeroes.png"               },
+  { "mole.digging.down.xpos",                          "8"                             },
+  { "mole.digging.down.ypos",                          "4"                             },
+  { "mole.digging.down.frames",                                "4"                             },
+  { "mole.digging.down.delay",                         "2"                             },
+  { "mole.digging.up",                                 "RocksHeroes.png"               },
+  { "mole.digging.up.xpos",                            "12"                            },
+  { "mole.digging.up.ypos",                            "4"                             },
+  { "mole.digging.up.frames",                          "4"                             },
+  { "mole.digging.up.delay",                           "2"                             },
+  { "mole.digging.left",                               "RocksHeroes.png"               },
+  { "mole.digging.left.xpos",                          "8"                             },
+  { "mole.digging.left.ypos",                          "5"                             },
+  { "mole.digging.left.frames",                                "4"                             },
+  { "mole.digging.left.delay",                         "2"                             },
+  { "mole.digging.right",                              "RocksHeroes.png"               },
+  { "mole.digging.right.xpos",                         "12"                            },
+  { "mole.digging.right.ypos",                         "5"                             },
+  { "mole.digging.right.frames",                       "4"                             },
+  { "mole.digging.right.delay",                                "2"                             },
+
+  { "penguin",                                         "RocksHeroes.png"               },
+  { "penguin.xpos",                                    "8"                             },
+  { "penguin.ypos",                                    "6"                             },
+  { "penguin.frames",                                  "1"                             },
+  { "penguin.down",                                    "RocksHeroes.png"               },
+  { "penguin.down.xpos",                               "8"                             },
+  { "penguin.down.ypos",                               "6"                             },
+  { "penguin.down.frames",                             "1"                             },
+  { "penguin.up",                                      "RocksHeroes.png"               },
+  { "penguin.up.xpos",                                 "12"                            },
+  { "penguin.up.ypos",                                 "6"                             },
+  { "penguin.up.frames",                               "1"                             },
+  { "penguin.left",                                    "RocksHeroes.png"               },
+  { "penguin.left.xpos",                               "8"                             },
+  { "penguin.left.ypos",                               "7"                             },
+  { "penguin.left.frames",                             "1"                             },
+  { "penguin.right",                                   "RocksHeroes.png"               },
+  { "penguin.right.xpos",                              "12"                            },
+  { "penguin.right.ypos",                              "7"                             },
+  { "penguin.right.frames",                            "1"                             },
+  { "penguin.moving.down",                             "RocksHeroes.png"               },
+  { "penguin.moving.down.xpos",                                "8"                             },
+  { "penguin.moving.down.ypos",                                "6"                             },
+  { "penguin.moving.down.frames",                      "4"                             },
+  { "penguin.moving.down.delay",                       "2"                             },
+  { "penguin.moving.up",                               "RocksHeroes.png"               },
+  { "penguin.moving.up.xpos",                          "12"                            },
+  { "penguin.moving.up.ypos",                          "6"                             },
+  { "penguin.moving.up.frames",                                "4"                             },
+  { "penguin.moving.up.delay",                         "2"                             },
+  { "penguin.moving.left",                             "RocksHeroes.png"               },
+  { "penguin.moving.left.xpos",                                "8"                             },
+  { "penguin.moving.left.ypos",                                "7"                             },
+  { "penguin.moving.left.frames",                      "4"                             },
+  { "penguin.moving.left.delay",                       "2"                             },
+  { "penguin.moving.right",                            "RocksHeroes.png"               },
+  { "penguin.moving.right.xpos",                       "12"                            },
+  { "penguin.moving.right.ypos",                       "7"                             },
+  { "penguin.moving.right.frames",                     "4"                             },
+  { "penguin.moving.right.delay",                      "2"                             },
+
+  { "satellite",                                       "RocksHeroes.png"               },
+  { "satellite.xpos",                                  "8"                             },
+  { "satellite.ypos",                                  "9"                             },
+  { "satellite.frames",                                        "8"                             },
+  { "satellite.delay",                                 "2"                             },
+  { "satellite.global_sync",                           "true"                          },
+
+  { "flames_1_left",                                   "RocksHeroes.png"               },
+  { "flames_1_left.xpos",                              "8"                             },
+  { "flames_1_left.ypos",                              "12"                            },
+  { "flames_1_left.frames",                            "2"                             },
+  { "flames_1_left.offset",                            "96"                            },
+  { "flames_2_left",                                   "RocksHeroes.png"               },
+  { "flames_2_left.xpos",                              "9"                             },
+  { "flames_2_left.ypos",                              "12"                            },
+  { "flames_2_left.frames",                            "2"                             },
+  { "flames_2_left.offset",                            "96"                            },
+  { "flames_3_left",                                   "RocksHeroes.png"               },
+  { "flames_3_left.xpos",                              "10"                            },
+  { "flames_3_left.ypos",                              "12"                            },
+  { "flames_3_left.frames",                            "2"                             },
+  { "flames_3_left.offset",                            "96"                            },
+
+  { "flames_1_right",                                  "RocksHeroes.png"               },
+  { "flames_1_right.xpos",                             "8"                             },
+  { "flames_1_right.ypos",                             "13"                            },
+  { "flames_1_right.frames",                           "2"                             },
+  { "flames_1_right.offset",                           "96"                            },
+  { "flames_2_right",                                  "RocksHeroes.png"               },
+  { "flames_2_right.xpos",                             "9"                             },
+  { "flames_2_right.ypos",                             "13"                            },
+  { "flames_2_right.frames",                           "2"                             },
+  { "flames_2_right.offset",                           "96"                            },
+  { "flames_3_right",                                  "RocksHeroes.png"               },
+  { "flames_3_right.xpos",                             "10"                            },
+  { "flames_3_right.ypos",                             "13"                            },
+  { "flames_3_right.frames",                           "2"                             },
+  { "flames_3_right.offset",                           "96"                            },
+
+  { "flames_1_up",                                     "RocksHeroes.png"               },
+  { "flames_1_up.xpos",                                        "8"                             },
+  { "flames_1_up.ypos",                                        "14"                            },
+  { "flames_1_up.frames",                              "2"                             },
+  { "flames_1_up.offset",                              "96"                            },
+  { "flames_2_up",                                     "RocksHeroes.png"               },
+  { "flames_2_up.xpos",                                        "9"                             },
+  { "flames_2_up.ypos",                                        "14"                            },
+  { "flames_2_up.frames",                              "2"                             },
+  { "flames_2_up.offset",                              "96"                            },
+  { "flames_3_up",                                     "RocksHeroes.png"               },
+  { "flames_3_up.xpos",                                        "10"                            },
+  { "flames_3_up.ypos",                                        "14"                            },
+  { "flames_3_up.frames",                              "2"                             },
+  { "flames_3_up.offset",                              "96"                            },
+
+  { "flames_1_down",                                   "RocksHeroes.png"               },
+  { "flames_1_down.xpos",                              "8"                             },
+  { "flames_1_down.ypos",                              "15"                            },
+  { "flames_1_down.frames",                            "2"                             },
+  { "flames_1_down.offset",                            "96"                            },
+  { "flames_2_down",                                   "RocksHeroes.png"               },
+  { "flames_2_down.xpos",                              "9"                             },
+  { "flames_2_down.ypos",                              "15"                            },
+  { "flames_2_down.frames",                            "2"                             },
+  { "flames_2_down.offset",                            "96"                            },
+  { "flames_3_down",                                   "RocksHeroes.png"               },
+  { "flames_3_down.xpos",                              "10"                            },
+  { "flames_3_down.ypos",                              "15"                            },
+  { "flames_3_down.frames",                            "2"                             },
+  { "flames_3_down.offset",                            "96"                            },
+
+  { "stoneblock",                                      "RocksElements.png"             },
+  { "stoneblock.xpos",                                 "10"                            },
+  { "stoneblock.ypos",                                 "1"                             },
+  { "stoneblock.frames",                               "1"                             },
 
   // images for other elements and actions
 
-  { "player_1",                                        "RocksHeroes.png"       },
-  { "player_1.xpos",                           "0"                     },
-  { "player_1.ypos",                           "0"                     },
-  { "player_1.frames",                         "1"                     },
-  { "player_1.down",                           "RocksHeroes.png"       },
-  { "player_1.down.xpos",                      "0"                     },
-  { "player_1.down.ypos",                      "0"                     },
-  { "player_1.down.frames",                    "1"                     },
-  { "player_1.up",                             "RocksHeroes.png"       },
-  { "player_1.up.xpos",                                "4"                     },
-  { "player_1.up.ypos",                                "0"                     },
-  { "player_1.up.frames",                      "1"                     },
-  { "player_1.left",                           "RocksHeroes.png"       },
-  { "player_1.left.xpos",                      "0"                     },
-  { "player_1.left.ypos",                      "1"                     },
-  { "player_1.left.frames",                    "1"                     },
-  { "player_1.right",                          "RocksHeroes.png"       },
-  { "player_1.right.xpos",                     "4"                     },
-  { "player_1.right.ypos",                     "1"                     },
-  { "player_1.right.frames",                   "1"                     },
-  { "player_1.moving.down",                    "RocksHeroes.png"       },
-  { "player_1.moving.down.xpos",               "0"                     },
-  { "player_1.moving.down.ypos",               "0"                     },
-  { "player_1.moving.down.frames",             "4"                     },
-  { "player_1.moving.down.start_frame",                "1"                     },
-  { "player_1.moving.down.delay",              "4"                     },
-  { "player_1.moving.up",                      "RocksHeroes.png"       },
-  { "player_1.moving.up.xpos",                 "4"                     },
-  { "player_1.moving.up.ypos",                 "0"                     },
-  { "player_1.moving.up.frames",               "4"                     },
-  { "player_1.moving.up.start_frame",          "1"                     },
-  { "player_1.moving.up.delay",                        "4"                     },
-  { "player_1.moving.left",                    "RocksHeroes.png"       },
-  { "player_1.moving.left.xpos",               "0"                     },
-  { "player_1.moving.left.ypos",               "1"                     },
-  { "player_1.moving.left.frames",             "4"                     },
-  { "player_1.moving.left.start_frame",                "1"                     },
-  { "player_1.moving.left.delay",              "4"                     },
-  { "player_1.moving.right",                   "RocksHeroes.png"       },
-  { "player_1.moving.right.xpos",              "4"                     },
-  { "player_1.moving.right.ypos",              "1"                     },
-  { "player_1.moving.right.frames",            "4"                     },
-  { "player_1.moving.right.start_frame",       "1"                     },
-  { "player_1.moving.right.delay",             "4"                     },
-  { "player_1.digging.down",                   "RocksHeroes.png"       },
-  { "player_1.digging.down.xpos",              "0"                     },
-  { "player_1.digging.down.ypos",              "0"                     },
-  { "player_1.digging.down.frames",            "4"                     },
-  { "player_1.digging.down.start_frame",       "1"                     },
-  { "player_1.digging.down.delay",             "4"                     },
-  { "player_1.digging.up",                     "RocksHeroes.png"       },
-  { "player_1.digging.up.xpos",                        "4"                     },
-  { "player_1.digging.up.ypos",                        "0"                     },
-  { "player_1.digging.up.frames",              "4"                     },
-  { "player_1.digging.up.start_frame",         "1"                     },
-  { "player_1.digging.up.delay",               "4"                     },
-  { "player_1.digging.left",                   "RocksHeroes.png"       },
-  { "player_1.digging.left.xpos",              "0"                     },
-  { "player_1.digging.left.ypos",              "1"                     },
-  { "player_1.digging.left.frames",            "4"                     },
-  { "player_1.digging.left.start_frame",       "1"                     },
-  { "player_1.digging.left.delay",             "4"                     },
-  { "player_1.digging.right",                  "RocksHeroes.png"       },
-  { "player_1.digging.right.xpos",             "4"                     },
-  { "player_1.digging.right.ypos",             "1"                     },
-  { "player_1.digging.right.frames",           "4"                     },
-  { "player_1.digging.right.start_frame",      "1"                     },
-  { "player_1.digging.right.delay",            "4"                     },
-  { "player_1.collecting.down",                        "RocksHeroes.png"       },
-  { "player_1.collecting.down.xpos",           "0"                     },
-  { "player_1.collecting.down.ypos",           "0"                     },
-  { "player_1.collecting.down.frames",         "4"                     },
-  { "player_1.collecting.down.start_frame",    "1"                     },
-  { "player_1.collecting.down.delay",          "4"                     },
-  { "player_1.collecting.up",                  "RocksHeroes.png"       },
-  { "player_1.collecting.up.xpos",             "4"                     },
-  { "player_1.collecting.up.ypos",             "0"                     },
-  { "player_1.collecting.up.frames",           "4"                     },
-  { "player_1.collecting.up.start_frame",      "1"                     },
-  { "player_1.collecting.up.delay",            "4"                     },
-  { "player_1.collecting.left",                        "RocksHeroes.png"       },
-  { "player_1.collecting.left.xpos",           "0"                     },
-  { "player_1.collecting.left.ypos",           "1"                     },
-  { "player_1.collecting.left.frames",         "4"                     },
-  { "player_1.collecting.left.start_frame",    "1"                     },
-  { "player_1.collecting.left.delay",          "4"                     },
-  { "player_1.collecting.right",               "RocksHeroes.png"       },
-  { "player_1.collecting.right.xpos",          "4"                     },
-  { "player_1.collecting.right.ypos",          "1"                     },
-  { "player_1.collecting.right.frames",                "4"                     },
-  { "player_1.collecting.right.start_frame",   "1"                     },
-  { "player_1.collecting.right.delay",         "4"                     },
-  { "player_1.pushing.down",                   "RocksHeroes.png"       },
-  { "player_1.pushing.down.xpos",              "0"                     },
-  { "player_1.pushing.down.ypos",              "0"                     },
-  { "player_1.pushing.down.frames",            "4"                     },
-  { "player_1.pushing.down.delay",             "4"                     },
-  { "player_1.pushing.up",                     "RocksHeroes.png"       },
-  { "player_1.pushing.up.xpos",                        "4"                     },
-  { "player_1.pushing.up.ypos",                        "0"                     },
-  { "player_1.pushing.up.frames",              "4"                     },
-  { "player_1.pushing.up.delay",               "4"                     },
-  { "player_1.pushing.left",                   "RocksHeroes.png"       },
-  { "player_1.pushing.left.xpos",              "4"                     },
-  { "player_1.pushing.left.ypos",              "2"                     },
-  { "player_1.pushing.left.frames",            "4"                     },
-  { "player_1.pushing.left.delay",             "4"                     },
-  { "player_1.pushing.right",                  "RocksHeroes.png"       },
-  { "player_1.pushing.right.xpos",             "0"                     },
-  { "player_1.pushing.right.ypos",             "2"                     },
-  { "player_1.pushing.right.frames",           "4"                     },
-  { "player_1.pushing.right.delay",            "4"                     },
-  { "player_1.snapping.down",                  "RocksHeroes.png"       },
-  { "player_1.snapping.down.xpos",             "0"                     },
-  { "player_1.snapping.down.ypos",             "0"                     },
-  { "player_1.snapping.down.frames",           "1"                     },
-  { "player_1.snapping.up",                    "RocksHeroes.png"       },
-  { "player_1.snapping.up.xpos",               "4"                     },
-  { "player_1.snapping.up.ypos",               "0"                     },
-  { "player_1.snapping.up.frames",             "1"                     },
-  { "player_1.snapping.left",                  "RocksHeroes.png"       },
-  { "player_1.snapping.left.xpos",             "0"                     },
-  { "player_1.snapping.left.ypos",             "1"                     },
-  { "player_1.snapping.left.frames",           "1"                     },
-  { "player_1.snapping.right",                 "RocksHeroes.png"       },
-  { "player_1.snapping.right.xpos",            "4"                     },
-  { "player_1.snapping.right.ypos",            "1"                     },
-  { "player_1.snapping.right.frames",          "1"                     },
-
-  { "player_2",                                        "RocksHeroes.png"       },
-  { "player_2.xpos",                           "0"                     },
-  { "player_2.ypos",                           "3"                     },
-  { "player_2.frames",                         "1"                     },
-  { "player_2.down",                           "RocksHeroes.png"       },
-  { "player_2.down.xpos",                      "0"                     },
-  { "player_2.down.ypos",                      "3"                     },
-  { "player_2.down.frames",                    "1"                     },
-  { "player_2.up",                             "RocksHeroes.png"       },
-  { "player_2.up.xpos",                                "4"                     },
-  { "player_2.up.ypos",                                "3"                     },
-  { "player_2.up.frames",                      "1"                     },
-  { "player_2.left",                           "RocksHeroes.png"       },
-  { "player_2.left.xpos",                      "0"                     },
-  { "player_2.left.ypos",                      "4"                     },
-  { "player_2.left.frames",                    "1"                     },
-  { "player_2.right",                          "RocksHeroes.png"       },
-  { "player_2.right.xpos",                     "4"                     },
-  { "player_2.right.ypos",                     "4"                     },
-  { "player_2.right.frames",                   "1"                     },
-  { "player_2.moving.down",                    "RocksHeroes.png"       },
-  { "player_2.moving.down.xpos",               "0"                     },
-  { "player_2.moving.down.ypos",               "3"                     },
-  { "player_2.moving.down.frames",             "4"                     },
-  { "player_2.moving.down.start_frame",                "1"                     },
-  { "player_2.moving.down.delay",              "4"                     },
-  { "player_2.moving.up",                      "RocksHeroes.png"       },
-  { "player_2.moving.up.xpos",                 "4"                     },
-  { "player_2.moving.up.ypos",                 "3"                     },
-  { "player_2.moving.up.frames",               "4"                     },
-  { "player_2.moving.up.start_frame",          "1"                     },
-  { "player_2.moving.up.delay",                        "4"                     },
-  { "player_2.moving.left",                    "RocksHeroes.png"       },
-  { "player_2.moving.left.xpos",               "0"                     },
-  { "player_2.moving.left.ypos",               "4"                     },
-  { "player_2.moving.left.frames",             "4"                     },
-  { "player_2.moving.left.start_frame",                "1"                     },
-  { "player_2.moving.left.delay",              "4"                     },
-  { "player_2.moving.right",                   "RocksHeroes.png"       },
-  { "player_2.moving.right.xpos",              "4"                     },
-  { "player_2.moving.right.ypos",              "4"                     },
-  { "player_2.moving.right.frames",            "4"                     },
-  { "player_2.moving.right.start_frame",       "1"                     },
-  { "player_2.moving.right.delay",             "4"                     },
-  { "player_2.digging.down",                   "RocksHeroes.png"       },
-  { "player_2.digging.down.xpos",              "0"                     },
-  { "player_2.digging.down.ypos",              "3"                     },
-  { "player_2.digging.down.frames",            "4"                     },
-  { "player_2.digging.down.start_frame",       "1"                     },
-  { "player_2.digging.down.delay",             "4"                     },
-  { "player_2.digging.up",                     "RocksHeroes.png"       },
-  { "player_2.digging.up.xpos",                        "4"                     },
-  { "player_2.digging.up.ypos",                        "3"                     },
-  { "player_2.digging.up.frames",              "4"                     },
-  { "player_2.digging.up.start_frame",         "1"                     },
-  { "player_2.digging.up.delay",               "4"                     },
-  { "player_2.digging.left",                   "RocksHeroes.png"       },
-  { "player_2.digging.left.xpos",              "0"                     },
-  { "player_2.digging.left.ypos",              "4"                     },
-  { "player_2.digging.left.frames",            "4"                     },
-  { "player_2.digging.left.start_frame",       "1"                     },
-  { "player_2.digging.left.delay",             "4"                     },
-  { "player_2.digging.right",                  "RocksHeroes.png"       },
-  { "player_2.digging.right.xpos",             "4"                     },
-  { "player_2.digging.right.ypos",             "4"                     },
-  { "player_2.digging.right.frames",           "4"                     },
-  { "player_2.digging.right.start_frame",      "1"                     },
-  { "player_2.digging.right.delay",            "4"                     },
-  { "player_2.collecting.down",                        "RocksHeroes.png"       },
-  { "player_2.collecting.down.xpos",           "0"                     },
-  { "player_2.collecting.down.ypos",           "3"                     },
-  { "player_2.collecting.down.frames",         "4"                     },
-  { "player_2.collecting.down.start_frame",    "1"                     },
-  { "player_2.collecting.down.delay",          "4"                     },
-  { "player_2.collecting.up",                  "RocksHeroes.png"       },
-  { "player_2.collecting.up.xpos",             "4"                     },
-  { "player_2.collecting.up.ypos",             "3"                     },
-  { "player_2.collecting.up.frames",           "4"                     },
-  { "player_2.collecting.up.start_frame",      "1"                     },
-  { "player_2.collecting.up.delay",            "4"                     },
-  { "player_2.collecting.left",                        "RocksHeroes.png"       },
-  { "player_2.collecting.left.xpos",           "0"                     },
-  { "player_2.collecting.left.ypos",           "4"                     },
-  { "player_2.collecting.left.frames",         "4"                     },
-  { "player_2.collecting.left.start_frame",    "1"                     },
-  { "player_2.collecting.left.delay",          "4"                     },
-  { "player_2.collecting.right",               "RocksHeroes.png"       },
-  { "player_2.collecting.right.xpos",          "4"                     },
-  { "player_2.collecting.right.ypos",          "4"                     },
-  { "player_2.collecting.right.frames",                "4"                     },
-  { "player_2.collecting.right.start_frame",   "1"                     },
-  { "player_2.collecting.right.delay",         "4"                     },
-  { "player_2.pushing.down",                   "RocksHeroes.png"       },
-  { "player_2.pushing.down.xpos",              "0"                     },
-  { "player_2.pushing.down.ypos",              "3"                     },
-  { "player_2.pushing.down.frames",            "4"                     },
-  { "player_2.pushing.down.delay",             "4"                     },
-  { "player_2.pushing.up",                     "RocksHeroes.png"       },
-  { "player_2.pushing.up.xpos",                        "4"                     },
-  { "player_2.pushing.up.ypos",                        "3"                     },
-  { "player_2.pushing.up.frames",              "4"                     },
-  { "player_2.pushing.up.delay",               "4"                     },
-  { "player_2.pushing.left",                   "RocksHeroes.png"       },
-  { "player_2.pushing.left.xpos",              "4"                     },
-  { "player_2.pushing.left.ypos",              "5"                     },
-  { "player_2.pushing.left.frames",            "4"                     },
-  { "player_2.pushing.left.delay",             "4"                     },
-  { "player_2.pushing.right",                  "RocksHeroes.png"       },
-  { "player_2.pushing.right.xpos",             "0"                     },
-  { "player_2.pushing.right.ypos",             "5"                     },
-  { "player_2.pushing.right.frames",           "4"                     },
-  { "player_2.pushing.right.delay",            "4"                     },
-  { "player_2.snapping.down",                  "RocksHeroes.png"       },
-  { "player_2.snapping.down.xpos",             "0"                     },
-  { "player_2.snapping.down.ypos",             "3"                     },
-  { "player_2.snapping.down.frames",           "1"                     },
-  { "player_2.snapping.up",                    "RocksHeroes.png"       },
-  { "player_2.snapping.up.xpos",               "4"                     },
-  { "player_2.snapping.up.ypos",               "3"                     },
-  { "player_2.snapping.up.frames",             "1"                     },
-  { "player_2.snapping.left",                  "RocksHeroes.png"       },
-  { "player_2.snapping.left.xpos",             "0"                     },
-  { "player_2.snapping.left.ypos",             "4"                     },
-  { "player_2.snapping.left.frames",           "1"                     },
-  { "player_2.snapping.right",                 "RocksHeroes.png"       },
-  { "player_2.snapping.right.xpos",            "4"                     },
-  { "player_2.snapping.right.ypos",            "4"                     },
-  { "player_2.snapping.right.frames",          "1"                     },
-
-  { "player_3",                                        "RocksHeroes.png"       },
-  { "player_3.xpos",                           "0"                     },
-  { "player_3.ypos",                           "6"                     },
-  { "player_3.frames",                         "1"                     },
-  { "player_3.down",                           "RocksHeroes.png"       },
-  { "player_3.down.xpos",                      "0"                     },
-  { "player_3.down.ypos",                      "6"                     },
-  { "player_3.down.frames",                    "1"                     },
-  { "player_3.up",                             "RocksHeroes.png"       },
-  { "player_3.up.xpos",                                "4"                     },
-  { "player_3.up.ypos",                                "6"                     },
-  { "player_3.up.frames",                      "1"                     },
-  { "player_3.left",                           "RocksHeroes.png"       },
-  { "player_3.left.xpos",                      "0"                     },
-  { "player_3.left.ypos",                      "7"                     },
-  { "player_3.left.frames",                    "1"                     },
-  { "player_3.right",                          "RocksHeroes.png"       },
-  { "player_3.right.xpos",                     "4"                     },
-  { "player_3.right.ypos",                     "7"                     },
-  { "player_3.right.frames",                   "1"                     },
-  { "player_3.moving.down",                    "RocksHeroes.png"       },
-  { "player_3.moving.down.xpos",               "0"                     },
-  { "player_3.moving.down.ypos",               "6"                     },
-  { "player_3.moving.down.frames",             "4"                     },
-  { "player_3.moving.down.start_frame",                "1"                     },
-  { "player_3.moving.down.delay",              "4"                     },
-  { "player_3.moving.up",                      "RocksHeroes.png"       },
-  { "player_3.moving.up.xpos",                 "4"                     },
-  { "player_3.moving.up.ypos",                 "6"                     },
-  { "player_3.moving.up.frames",               "4"                     },
-  { "player_3.moving.up.start_frame",          "1"                     },
-  { "player_3.moving.up.delay",                        "4"                     },
-  { "player_3.moving.left",                    "RocksHeroes.png"       },
-  { "player_3.moving.left.xpos",               "0"                     },
-  { "player_3.moving.left.ypos",               "7"                     },
-  { "player_3.moving.left.frames",             "4"                     },
-  { "player_3.moving.left.start_frame",                "1"                     },
-  { "player_3.moving.left.delay",              "4"                     },
-  { "player_3.moving.right",                   "RocksHeroes.png"       },
-  { "player_3.moving.right.xpos",              "4"                     },
-  { "player_3.moving.right.ypos",              "7"                     },
-  { "player_3.moving.right.frames",            "4"                     },
-  { "player_3.moving.right.start_frame",       "1"                     },
-  { "player_3.moving.right.delay",             "4"                     },
-  { "player_3.digging.down",                   "RocksHeroes.png"       },
-  { "player_3.digging.down.xpos",              "0"                     },
-  { "player_3.digging.down.ypos",              "6"                     },
-  { "player_3.digging.down.frames",            "4"                     },
-  { "player_3.digging.down.start_frame",       "1"                     },
-  { "player_3.digging.down.delay",             "4"                     },
-  { "player_3.digging.up",                     "RocksHeroes.png"       },
-  { "player_3.digging.up.xpos",                        "4"                     },
-  { "player_3.digging.up.ypos",                        "6"                     },
-  { "player_3.digging.up.frames",              "4"                     },
-  { "player_3.digging.up.start_frame",         "1"                     },
-  { "player_3.digging.up.delay",               "4"                     },
-  { "player_3.digging.left",                   "RocksHeroes.png"       },
-  { "player_3.digging.left.xpos",              "0"                     },
-  { "player_3.digging.left.ypos",              "7"                     },
-  { "player_3.digging.left.frames",            "4"                     },
-  { "player_3.digging.left.start_frame",       "1"                     },
-  { "player_3.digging.left.delay",             "4"                     },
-  { "player_3.digging.right",                  "RocksHeroes.png"       },
-  { "player_3.digging.right.xpos",             "4"                     },
-  { "player_3.digging.right.ypos",             "7"                     },
-  { "player_3.digging.right.frames",           "4"                     },
-  { "player_3.digging.right.start_frame",      "1"                     },
-  { "player_3.digging.right.delay",            "4"                     },
-  { "player_3.collecting.down",                        "RocksHeroes.png"       },
-  { "player_3.collecting.down.xpos",           "0"                     },
-  { "player_3.collecting.down.ypos",           "6"                     },
-  { "player_3.collecting.down.frames",         "4"                     },
-  { "player_3.collecting.down.start_frame",    "1"                     },
-  { "player_3.collecting.down.delay",          "4"                     },
-  { "player_3.collecting.up",                  "RocksHeroes.png"       },
-  { "player_3.collecting.up.xpos",             "4"                     },
-  { "player_3.collecting.up.ypos",             "6"                     },
-  { "player_3.collecting.up.frames",           "4"                     },
-  { "player_3.collecting.up.start_frame",      "1"                     },
-  { "player_3.collecting.up.delay",            "4"                     },
-  { "player_3.collecting.left",                        "RocksHeroes.png"       },
-  { "player_3.collecting.left.xpos",           "0"                     },
-  { "player_3.collecting.left.ypos",           "7"                     },
-  { "player_3.collecting.left.frames",         "4"                     },
-  { "player_3.collecting.left.start_frame",    "1"                     },
-  { "player_3.collecting.left.delay",          "4"                     },
-  { "player_3.collecting.right",               "RocksHeroes.png"       },
-  { "player_3.collecting.right.xpos",          "4"                     },
-  { "player_3.collecting.right.ypos",          "7"                     },
-  { "player_3.collecting.right.frames",                "4"                     },
-  { "player_3.collecting.right.start_frame",   "1"                     },
-  { "player_3.collecting.right.delay",         "4"                     },
-  { "player_3.pushing.down",                   "RocksHeroes.png"       },
-  { "player_3.pushing.down.xpos",              "0"                     },
-  { "player_3.pushing.down.ypos",              "6"                     },
-  { "player_3.pushing.down.frames",            "4"                     },
-  { "player_3.pushing.down.delay",             "4"                     },
-  { "player_3.pushing.up",                     "RocksHeroes.png"       },
-  { "player_3.pushing.up.xpos",                        "4"                     },
-  { "player_3.pushing.up.ypos",                        "6"                     },
-  { "player_3.pushing.up.frames",              "4"                     },
-  { "player_3.pushing.up.delay",               "4"                     },
-  { "player_3.pushing.left",                   "RocksHeroes.png"       },
-  { "player_3.pushing.left.xpos",              "4"                     },
-  { "player_3.pushing.left.ypos",              "8"                     },
-  { "player_3.pushing.left.frames",            "4"                     },
-  { "player_3.pushing.left.delay",             "4"                     },
-  { "player_3.pushing.right",                  "RocksHeroes.png"       },
-  { "player_3.pushing.right.xpos",             "0"                     },
-  { "player_3.pushing.right.ypos",             "8"                     },
-  { "player_3.pushing.right.frames",           "4"                     },
-  { "player_3.pushing.right.delay",            "4"                     },
-  { "player_3.snapping.down",                  "RocksHeroes.png"       },
-  { "player_3.snapping.down.xpos",             "0"                     },
-  { "player_3.snapping.down.ypos",             "6"                     },
-  { "player_3.snapping.down.frames",           "1"                     },
-  { "player_3.snapping.up",                    "RocksHeroes.png"       },
-  { "player_3.snapping.up.xpos",               "4"                     },
-  { "player_3.snapping.up.ypos",               "6"                     },
-  { "player_3.snapping.up.frames",             "1"                     },
-  { "player_3.snapping.left",                  "RocksHeroes.png"       },
-  { "player_3.snapping.left.xpos",             "0"                     },
-  { "player_3.snapping.left.ypos",             "7"                     },
-  { "player_3.snapping.left.frames",           "1"                     },
-  { "player_3.snapping.right",                 "RocksHeroes.png"       },
-  { "player_3.snapping.right.xpos",            "4"                     },
-  { "player_3.snapping.right.ypos",            "7"                     },
-  { "player_3.snapping.right.frames",          "1"                     },
-
-  { "player_4",                                        "RocksHeroes.png"       },
-  { "player_4.xpos",                           "0"                     },
-  { "player_4.ypos",                           "9"                     },
-  { "player_4.frames",                         "1"                     },
-  { "player_4.down",                           "RocksHeroes.png"       },
-  { "player_4.down.xpos",                      "0"                     },
-  { "player_4.down.ypos",                      "9"                     },
-  { "player_4.down.frames",                    "1"                     },
-  { "player_4.up",                             "RocksHeroes.png"       },
-  { "player_4.up.xpos",                                "4"                     },
-  { "player_4.up.ypos",                                "9"                     },
-  { "player_4.up.frames",                      "1"                     },
-  { "player_4.left",                           "RocksHeroes.png"       },
-  { "player_4.left.xpos",                      "0"                     },
-  { "player_4.left.ypos",                      "10"                    },
-  { "player_4.left.frames",                    "1"                     },
-  { "player_4.right",                          "RocksHeroes.png"       },
-  { "player_4.right.xpos",                     "4"                     },
-  { "player_4.right.ypos",                     "10"                    },
-  { "player_4.right.frames",                   "1"                     },
-  { "player_4.moving.down",                    "RocksHeroes.png"       },
-  { "player_4.moving.down.xpos",               "0"                     },
-  { "player_4.moving.down.ypos",               "9"                     },
-  { "player_4.moving.down.frames",             "4"                     },
-  { "player_4.moving.down.start_frame",                "1"                     },
-  { "player_4.moving.down.delay",              "4"                     },
-  { "player_4.moving.up",                      "RocksHeroes.png"       },
-  { "player_4.moving.up.xpos",                 "4"                     },
-  { "player_4.moving.up.ypos",                 "9"                     },
-  { "player_4.moving.up.frames",               "4"                     },
-  { "player_4.moving.up.start_frame",          "1"                     },
-  { "player_4.moving.up.delay",                        "4"                     },
-  { "player_4.moving.left",                    "RocksHeroes.png"       },
-  { "player_4.moving.left.xpos",               "0"                     },
-  { "player_4.moving.left.ypos",               "10"                    },
-  { "player_4.moving.left.frames",             "4"                     },
-  { "player_4.moving.left.start_frame",                "1"                     },
-  { "player_4.moving.left.delay",              "4"                     },
-  { "player_4.moving.right",                   "RocksHeroes.png"       },
-  { "player_4.moving.right.xpos",              "4"                     },
-  { "player_4.moving.right.ypos",              "10"                    },
-  { "player_4.moving.right.frames",            "4"                     },
-  { "player_4.moving.right.start_frame",       "1"                     },
-  { "player_4.moving.right.delay",             "4"                     },
-  { "player_4.digging.down",                   "RocksHeroes.png"       },
-  { "player_4.digging.down.xpos",              "0"                     },
-  { "player_4.digging.down.ypos",              "9"                     },
-  { "player_4.digging.down.frames",            "4"                     },
-  { "player_4.digging.down.start_frame",       "1"                     },
-  { "player_4.digging.down.delay",             "4"                     },
-  { "player_4.digging.up",                     "RocksHeroes.png"       },
-  { "player_4.digging.up.xpos",                        "4"                     },
-  { "player_4.digging.up.ypos",                        "9"                     },
-  { "player_4.digging.up.frames",              "4"                     },
-  { "player_4.digging.up.start_frame",         "1"                     },
-  { "player_4.digging.up.delay",               "4"                     },
-  { "player_4.digging.left",                   "RocksHeroes.png"       },
-  { "player_4.digging.left.xpos",              "0"                     },
-  { "player_4.digging.left.ypos",              "10"                    },
-  { "player_4.digging.left.frames",            "4"                     },
-  { "player_4.digging.left.start_frame",       "1"                     },
-  { "player_4.digging.left.delay",             "4"                     },
-  { "player_4.digging.right",                  "RocksHeroes.png"       },
-  { "player_4.digging.right.xpos",             "4"                     },
-  { "player_4.digging.right.ypos",             "10"                    },
-  { "player_4.digging.right.frames",           "4"                     },
-  { "player_4.digging.right.start_frame",      "1"                     },
-  { "player_4.digging.right.delay",            "4"                     },
-  { "player_4.collecting.down",                        "RocksHeroes.png"       },
-  { "player_4.collecting.down.xpos",           "0"                     },
-  { "player_4.collecting.down.ypos",           "9"                     },
-  { "player_4.collecting.down.frames",         "4"                     },
-  { "player_4.collecting.down.start_frame",    "1"                     },
-  { "player_4.collecting.down.delay",          "4"                     },
-  { "player_4.collecting.up",                  "RocksHeroes.png"       },
-  { "player_4.collecting.up.xpos",             "4"                     },
-  { "player_4.collecting.up.ypos",             "9"                     },
-  { "player_4.collecting.up.frames",           "4"                     },
-  { "player_4.collecting.up.start_frame",      "1"                     },
-  { "player_4.collecting.up.delay",            "4"                     },
-  { "player_4.collecting.left",                        "RocksHeroes.png"       },
-  { "player_4.collecting.left.xpos",           "0"                     },
-  { "player_4.collecting.left.ypos",           "10"                    },
-  { "player_4.collecting.left.frames",         "4"                     },
-  { "player_4.collecting.left.start_frame",    "1"                     },
-  { "player_4.collecting.left.delay",          "4"                     },
-  { "player_4.collecting.right",               "RocksHeroes.png"       },
-  { "player_4.collecting.right.xpos",          "4"                     },
-  { "player_4.collecting.right.ypos",          "10"                    },
-  { "player_4.collecting.right.frames",                "4"                     },
-  { "player_4.collecting.right.start_frame",   "1"                     },
-  { "player_4.collecting.right.delay",         "4"                     },
-  { "player_4.pushing.down",                   "RocksHeroes.png"       },
-  { "player_4.pushing.down.xpos",              "0"                     },
-  { "player_4.pushing.down.ypos",              "9"                     },
-  { "player_4.pushing.down.frames",            "4"                     },
-  { "player_4.pushing.down.delay",             "4"                     },
-  { "player_4.pushing.up",                     "RocksHeroes.png"       },
-  { "player_4.pushing.up.xpos",                        "4"                     },
-  { "player_4.pushing.up.ypos",                        "9"                     },
-  { "player_4.pushing.up.frames",              "4"                     },
-  { "player_4.pushing.up.delay",               "4"                     },
-  { "player_4.pushing.left",                   "RocksHeroes.png"       },
-  { "player_4.pushing.left.xpos",              "4"                     },
-  { "player_4.pushing.left.ypos",              "11"                    },
-  { "player_4.pushing.left.frames",            "4"                     },
-  { "player_4.pushing.left.delay",             "4"                     },
-  { "player_4.pushing.right",                  "RocksHeroes.png"       },
-  { "player_4.pushing.right.xpos",             "0"                     },
-  { "player_4.pushing.right.ypos",             "11"                    },
-  { "player_4.pushing.right.frames",           "4"                     },
-  { "player_4.pushing.right.delay",            "4"                     },
-  { "player_4.snapping.down",                  "RocksHeroes.png"       },
-  { "player_4.snapping.down.xpos",             "0"                     },
-  { "player_4.snapping.down.ypos",             "9"                     },
-  { "player_4.snapping.down.frames",           "1"                     },
-  { "player_4.snapping.up",                    "RocksHeroes.png"       },
-  { "player_4.snapping.up.xpos",               "4"                     },
-  { "player_4.snapping.up.ypos",               "9"                     },
-  { "player_4.snapping.up.frames",             "1"                     },
-  { "player_4.snapping.left",                  "RocksHeroes.png"       },
-  { "player_4.snapping.left.xpos",             "0"                     },
-  { "player_4.snapping.left.ypos",             "10"                    },
-  { "player_4.snapping.left.frames",           "1"                     },
-  { "player_4.snapping.right",                 "RocksHeroes.png"       },
-  { "player_4.snapping.right.xpos",            "4"                     },
-  { "player_4.snapping.right.ypos",            "10"                    },
-  { "player_4.snapping.right.frames",          "1"                     },
-
-  { "[default].exploding",                     "RocksElements.png"     },
-  { "[default].exploding.xpos",                        "0"                     },
-  { "[default].exploding.ypos",                        "4"                     },
-  { "[default].exploding.frames",              "8"                     },
-  { "[default].exploding.delay",               "2"                     },
-  { "[default].exploding.anim_mode",           "linear"                },
-
-  { "twinkle_blue",                            "RocksHeroes.png"       },
-  { "twinkle_blue.xpos",                       "9"                     },
-  { "twinkle_blue.ypos",                       "11"                    },
-  { "twinkle_blue.frames",                     "3"                     },
-  { "twinkle_blue.delay",                      "2"                     },
-  { "twinkle_blue.anim_mode",                  "pingpong"              },
-  { "twinkle_blue.global_sync",                        "false"                 },
-  { "twinkle_white",                           "RocksHeroes.png"       },
-  { "twinkle_white.xpos",                      "13"                    },
-  { "twinkle_white.ypos",                      "11"                    },
-  { "twinkle_white.frames",                    "3"                     },
-  { "twinkle_white.delay",                     "2"                     },
-  { "twinkle_white.anim_mode",                 "pingpong"              },
-  { "twinkle_white.global_sync",               "false"                 },
-
-  { "steelwall_topleft",                       "RocksElements.png"     },
-  { "steelwall_topleft.xpos",                  "4"                     },
-  { "steelwall_topleft.ypos",                  "0"                     },
-  { "steelwall_topleft.frames",                        "1"                     },
-  { "steelwall_topright",                      "RocksElements.png"     },
-  { "steelwall_topright.xpos",                 "4"                     },
-  { "steelwall_topright.ypos",                 "0"                     },
-  { "steelwall_topright.frames",               "1"                     },
-  { "steelwall_bottomleft",                    "RocksElements.png"     },
-  { "steelwall_bottomleft.xpos",               "4"                     },
-  { "steelwall_bottomleft.ypos",               "0"                     },
-  { "steelwall_bottomleft.frames",             "1"                     },
-  { "steelwall_bottomright",                   "RocksElements.png"     },
-  { "steelwall_bottomright.xpos",              "4"                     },
-  { "steelwall_bottomright.ypos",              "0"                     },
-  { "steelwall_bottomright.frames",            "1"                     },
-  { "steelwall_horizontal",                    "RocksElements.png"     },
-  { "steelwall_horizontal.xpos",               "4"                     },
-  { "steelwall_horizontal.ypos",               "0"                     },
-  { "steelwall_horizontal.frames",             "1"                     },
-  { "steelwall_vertical",                      "RocksElements.png"     },
-  { "steelwall_vertical.xpos",                 "4"                     },
-  { "steelwall_vertical.ypos",                 "0"                     },
-  { "steelwall_vertical.frames",               "1"                     },
-
-  { "steelwall_topleft.EDITOR",                        "RocksElements.png"     },
-  { "steelwall_topleft.EDITOR.xpos",           "0"                     },
-  { "steelwall_topleft.EDITOR.ypos",           "13"                    },
-  { "steelwall_topright.EDITOR",               "RocksElements.png"     },
-  { "steelwall_topright.EDITOR.xpos",          "1"                     },
-  { "steelwall_topright.EDITOR.ypos",          "13"                    },
-  { "steelwall_bottomleft.EDITOR",             "RocksElements.png"     },
-  { "steelwall_bottomleft.EDITOR.xpos",                "2"                     },
-  { "steelwall_bottomleft.EDITOR.ypos",                "13"                    },
-  { "steelwall_bottomright.EDITOR",            "RocksElements.png"     },
-  { "steelwall_bottomright.EDITOR.xpos",       "3"                     },
-  { "steelwall_bottomright.EDITOR.ypos",       "13"                    },
-  { "steelwall_horizontal.EDITOR",             "RocksElements.png"     },
-  { "steelwall_horizontal.EDITOR.xpos",                "4"                     },
-  { "steelwall_horizontal.EDITOR.ypos",                "13"                    },
-  { "steelwall_vertical.EDITOR",               "RocksElements.png"     },
-  { "steelwall_vertical.EDITOR.xpos",          "5"                     },
-  { "steelwall_vertical.EDITOR.ypos",          "13"                    },
-
-  { "invisible_steelwall_topleft",             "RocksSP.png"           },
-  { "invisible_steelwall_topleft.xpos",                "0"                     },
-  { "invisible_steelwall_topleft.ypos",                "0"                     },
-  { "invisible_steelwall_topleft.frames",      "1"                     },
-  { "invisible_steelwall_topright",            "RocksSP.png"           },
-  { "invisible_steelwall_topright.xpos",       "0"                     },
-  { "invisible_steelwall_topright.ypos",       "0"                     },
-  { "invisible_steelwall_topright.frames",     "1"                     },
-  { "invisible_steelwall_bottomleft",          "RocksSP.png"           },
-  { "invisible_steelwall_bottomleft.xpos",     "0"                     },
-  { "invisible_steelwall_bottomleft.ypos",     "0"                     },
-  { "invisible_steelwall_bottomleft.frames",   "1"                     },
-  { "invisible_steelwall_bottomright",         "RocksSP.png"           },
-  { "invisible_steelwall_bottomright.xpos",    "0"                     },
-  { "invisible_steelwall_bottomright.ypos",    "0"                     },
-  { "invisible_steelwall_bottomright.frames",  "1"                     },
-  { "invisible_steelwall_horizontal",          "RocksSP.png"           },
-  { "invisible_steelwall_horizontal.xpos",     "0"                     },
-  { "invisible_steelwall_horizontal.ypos",     "0"                     },
-  { "invisible_steelwall_horizontal.frames",   "1"                     },
-  { "invisible_steelwall_vertical",            "RocksSP.png"           },
-  { "invisible_steelwall_vertical.xpos",       "0"                     },
-  { "invisible_steelwall_vertical.ypos",       "0"                     },
-  { "invisible_steelwall_vertical.frames",     "1"                     },
-
-  { "invisible_steelwall_topleft.EDITOR",      "RocksElements.png"     },
-  { "invisible_steelwall_topleft.EDITOR.xpos", "6"                     },
-  { "invisible_steelwall_topleft.EDITOR.ypos", "13"                    },
-  { "invisible_steelwall_topright.EDITOR",     "RocksElements.png"     },
-  { "invisible_steelwall_topright.EDITOR.xpos",        "7"                     },
-  { "invisible_steelwall_topright.EDITOR.ypos",        "13"                    },
-  { "invisible_steelwall_bottomleft.EDITOR",   "RocksElements.png"     },
-  { "invisible_steelwall_bottomleft.EDITOR.xpos","8"                   },
-  { "invisible_steelwall_bottomleft.EDITOR.ypos","13"                  },
-  { "invisible_steelwall_bottomright.EDITOR",  "RocksElements.png"     },
-  { "invisible_steelwall_bottomright.EDITOR.xpos","9"                  },
-  { "invisible_steelwall_bottomright.EDITOR.ypos","13"                 },
-  { "invisible_steelwall_horizontal.EDITOR",   "RocksElements.png"     },
-  { "invisible_steelwall_horizontal.EDITOR.xpos","10"                  },
-  { "invisible_steelwall_horizontal.EDITOR.ypos","13"                  },
-  { "invisible_steelwall_vertical.EDITOR",     "RocksElements.png"     },
-  { "invisible_steelwall_vertical.EDITOR.xpos",        "11"                    },
-  { "invisible_steelwall_vertical.EDITOR.ypos",        "13"                    },
-
-  { "arrow_left",                              "RocksDC.png"           },
-  { "arrow_left.xpos",                         "8"                     },
-  { "arrow_left.ypos",                         "8"                     },
-  { "arrow_left.frames",                       "1"                     },
-  { "arrow_right",                             "RocksDC.png"           },
-  { "arrow_right.xpos",                                "9"                     },
-  { "arrow_right.ypos",                                "8"                     },
-  { "arrow_right.frames",                      "1"                     },
-  { "arrow_up",                                        "RocksDC.png"           },
-  { "arrow_up.xpos",                           "10"                    },
-  { "arrow_up.ypos",                           "8"                     },
-  { "arrow_up.frames",                         "1"                     },
-  { "arrow_down",                              "RocksDC.png"           },
-  { "arrow_down.xpos",                         "11"                    },
-  { "arrow_down.ypos",                         "8"                     },
-  { "arrow_down.frames",                       "1"                     },
-
-  { "unknown",                                 "RocksFontEM.png"       },
-  { "unknown.xpos",                            "15"                    },
-  { "unknown.ypos",                            "1"                     },
-  { "unknown.frames",                          "1"                     },
-
-  { "trigger_element",                         "RocksDC.png"           },
-  { "trigger_element.xpos",                    "15"                    },
-  { "trigger_element.ypos",                    "14"                    },
-  { "trigger_element.frames",                  "1"                     },
-
-  { "trigger_player",                          "RocksDC.png"           },
-  { "trigger_player.xpos",                     "15"                    },
-  { "trigger_player.ypos",                     "13"                    },
-  { "trigger_player.frames",                   "1"                     },
-
-  { "trigger_ce_value",                                "RocksDC.png"           },
-  { "trigger_ce_value.xpos",                   "15"                    },
-  { "trigger_ce_value.ypos",                   "11"                    },
-  { "trigger_ce_value.frames",                 "1"                     },
-
-  { "trigger_ce_score",                                "RocksDC.png"           },
-  { "trigger_ce_score.xpos",                   "15"                    },
-  { "trigger_ce_score.ypos",                   "12"                    },
-  { "trigger_ce_score.frames",                 "1"                     },
-
-  { "current_ce_value",                                "RocksDC.png"           },
-  { "current_ce_value.xpos",                   "14"                    },
-  { "current_ce_value.ypos",                   "11"                    },
-  { "current_ce_value.frames",                 "1"                     },
-
-  { "current_ce_score",                                "RocksDC.png"           },
-  { "current_ce_score.xpos",                   "14"                    },
-  { "current_ce_score.ypos",                   "12"                    },
-  { "current_ce_score.frames",                 "1"                     },
-
-  { "prev_ce_1",                               "RocksMore.png"         },
-  { "prev_ce_1.xpos",                          "0"                     },
-  { "prev_ce_1.ypos",                          "7"                     },
-  { "prev_ce_1.frames",                                "1"                     },
-
-  { "prev_ce_2",                               "RocksMore.png"         },
-  { "prev_ce_2.xpos",                          "1"                     },
-  { "prev_ce_2.ypos",                          "7"                     },
-  { "prev_ce_2.frames",                                "1"                     },
-
-  { "prev_ce_3",                               "RocksMore.png"         },
-  { "prev_ce_3.xpos",                          "2"                     },
-  { "prev_ce_3.ypos",                          "7"                     },
-  { "prev_ce_3.frames",                                "1"                     },
-
-  { "prev_ce_4",                               "RocksMore.png"         },
-  { "prev_ce_4.xpos",                          "3"                     },
-  { "prev_ce_4.ypos",                          "7"                     },
-  { "prev_ce_4.frames",                                "1"                     },
-
-  { "prev_ce_5",                               "RocksMore.png"         },
-  { "prev_ce_5.xpos",                          "4"                     },
-  { "prev_ce_5.ypos",                          "7"                     },
-  { "prev_ce_5.frames",                                "1"                     },
-
-  { "prev_ce_6",                               "RocksMore.png"         },
-  { "prev_ce_6.xpos",                          "5"                     },
-  { "prev_ce_6.ypos",                          "7"                     },
-  { "prev_ce_6.frames",                                "1"                     },
-
-  { "prev_ce_7",                               "RocksMore.png"         },
-  { "prev_ce_7.xpos",                          "6"                     },
-  { "prev_ce_7.ypos",                          "7"                     },
-  { "prev_ce_7.frames",                                "1"                     },
-
-  { "prev_ce_8",                               "RocksMore.png"         },
-  { "prev_ce_8.xpos",                          "7"                     },
-  { "prev_ce_8.ypos",                          "7"                     },
-  { "prev_ce_8.frames",                                "1"                     },
-
-  { "next_ce_1",                               "RocksMore.png"         },
-  { "next_ce_1.xpos",                          "0"                     },
-  { "next_ce_1.ypos",                          "8"                     },
-  { "next_ce_1.frames",                                "1"                     },
-
-  { "next_ce_2",                               "RocksMore.png"         },
-  { "next_ce_2.xpos",                          "1"                     },
-  { "next_ce_2.ypos",                          "8"                     },
-  { "next_ce_2.frames",                                "1"                     },
-
-  { "next_ce_3",                               "RocksMore.png"         },
-  { "next_ce_3.xpos",                          "2"                     },
-  { "next_ce_3.ypos",                          "8"                     },
-  { "next_ce_3.frames",                                "1"                     },
-
-  { "next_ce_4",                               "RocksMore.png"         },
-  { "next_ce_4.xpos",                          "3"                     },
-  { "next_ce_4.ypos",                          "8"                     },
-  { "next_ce_4.frames",                                "1"                     },
-
-  { "next_ce_5",                               "RocksMore.png"         },
-  { "next_ce_5.xpos",                          "4"                     },
-  { "next_ce_5.ypos",                          "8"                     },
-  { "next_ce_5.frames",                                "1"                     },
-
-  { "next_ce_6",                               "RocksMore.png"         },
-  { "next_ce_6.xpos",                          "5"                     },
-  { "next_ce_6.ypos",                          "8"                     },
-  { "next_ce_6.frames",                                "1"                     },
-
-  { "next_ce_7",                               "RocksMore.png"         },
-  { "next_ce_7.xpos",                          "6"                     },
-  { "next_ce_7.ypos",                          "8"                     },
-  { "next_ce_7.frames",                                "1"                     },
-
-  { "next_ce_8",                               "RocksMore.png"         },
-  { "next_ce_8.xpos",                          "7"                     },
-  { "next_ce_8.ypos",                          "8"                     },
-  { "next_ce_8.frames",                                "1"                     },
-
-  { "self",                                    "RocksMore.png"         },
-  { "self.xpos",                               "8"                     },
-  { "self.ypos",                               "7"                     },
-  { "self.frames",                             "1"                     },
-
-  { "any_element",                             "RocksMore.png"         },
-  { "any_element.xpos",                                "9"                     },
-  { "any_element.ypos",                                "7"                     },
-  { "any_element.frames",                      "1"                     },
-
-  { "emc_key_5",                               "RocksEMC.png"          },
-  { "emc_key_5.xpos",                          "0"                     },
-  { "emc_key_5.ypos",                          "5"                     },
-  { "emc_key_5.frames",                                "1"                     },
-  { "emc_key_5.collecting",                    "RocksCollect.png"      },
-  { "emc_key_5.collecting.xpos",               "7"                     },
-  { "emc_key_5.collecting.ypos",               "12"                    },
-  { "emc_key_5.collecting.frames",             "7"                     },
-  { "emc_key_5.collecting.anim_mode",          "linear"                },
-  { "emc_key_6",                               "RocksEMC.png"          },
-  { "emc_key_6.xpos",                          "1"                     },
-  { "emc_key_6.ypos",                          "5"                     },
-  { "emc_key_6.frames",                                "1"                     },
-  { "emc_key_6.collecting",                    "RocksCollect.png"      },
-  { "emc_key_6.collecting.xpos",               "7"                     },
-  { "emc_key_6.collecting.ypos",               "13"                    },
-  { "emc_key_6.collecting.frames",             "7"                     },
-  { "emc_key_6.collecting.anim_mode",          "linear"                },
-  { "emc_key_7",                               "RocksEMC.png"          },
-  { "emc_key_7.xpos",                          "2"                     },
-  { "emc_key_7.ypos",                          "5"                     },
-  { "emc_key_7.frames",                                "1"                     },
-  { "emc_key_7.collecting",                    "RocksCollect.png"      },
-  { "emc_key_7.collecting.xpos",               "7"                     },
-  { "emc_key_7.collecting.ypos",               "14"                    },
-  { "emc_key_7.collecting.frames",             "7"                     },
-  { "emc_key_7.collecting.anim_mode",          "linear"                },
-  { "emc_key_8",                               "RocksEMC.png"          },
-  { "emc_key_8.xpos",                          "3"                     },
-  { "emc_key_8.ypos",                          "5"                     },
-  { "emc_key_8.frames",                                "1"                     },
-  { "emc_key_8.collecting",                    "RocksCollect.png"      },
-  { "emc_key_8.collecting.xpos",               "7"                     },
-  { "emc_key_8.collecting.ypos",               "15"                    },
-  { "emc_key_8.collecting.frames",             "7"                     },
-  { "emc_key_8.collecting.anim_mode",          "linear"                },
-
-  { "emc_gate_5",                              "RocksEMC.png"          },
-  { "emc_gate_5.xpos",                         "0"                     },
-  { "emc_gate_5.ypos",                         "6"                     },
-  { "emc_gate_5.frames",                       "1"                     },
-  { "emc_gate_6",                              "RocksEMC.png"          },
-  { "emc_gate_6.xpos",                         "1"                     },
-  { "emc_gate_6.ypos",                         "6"                     },
-  { "emc_gate_6.frames",                       "1"                     },
-  { "emc_gate_7",                              "RocksEMC.png"          },
-  { "emc_gate_7.xpos",                         "2"                     },
-  { "emc_gate_7.ypos",                         "6"                     },
-  { "emc_gate_7.frames",                       "1"                     },
-  { "emc_gate_8",                              "RocksEMC.png"          },
-  { "emc_gate_8.xpos",                         "3"                     },
-  { "emc_gate_8.ypos",                         "6"                     },
-  { "emc_gate_8.frames",                       "1"                     },
-  { "emc_gate_5_gray",                         "RocksEMC.png"          },
-  { "emc_gate_5_gray.xpos",                    "4"                     },
-  { "emc_gate_5_gray.ypos",                    "7"                     },
-  { "emc_gate_5_gray.frames",                  "1"                     },
-  { "emc_gate_5_gray.EDITOR",                  "RocksEMC.png"          },
-  { "emc_gate_5_gray.EDITOR.xpos",             "0"                     },
-  { "emc_gate_5_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_5_gray.active",                  "RocksEMC.png"          },
-  { "emc_gate_5_gray.active.xpos",             "0"                     },
-  { "emc_gate_5_gray.active.ypos",             "6"                     },
-  { "emc_gate_5_gray.active.frames",           "1"                     },
-  { "emc_gate_6_gray",                         "RocksEMC.png"          },
-  { "emc_gate_6_gray.xpos",                    "4"                     },
-  { "emc_gate_6_gray.ypos",                    "7"                     },
-  { "emc_gate_6_gray.frames",                  "1"                     },
-  { "emc_gate_6_gray.EDITOR",                  "RocksEMC.png"          },
-  { "emc_gate_6_gray.EDITOR.xpos",             "1"                     },
-  { "emc_gate_6_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_6_gray.active",                  "RocksEMC.png"          },
-  { "emc_gate_6_gray.active.xpos",             "1"                     },
-  { "emc_gate_6_gray.active.ypos",             "6"                     },
-  { "emc_gate_6_gray.active.frames",           "1"                     },
-  { "emc_gate_7_gray",                         "RocksEMC.png"          },
-  { "emc_gate_7_gray.xpos",                    "4"                     },
-  { "emc_gate_7_gray.ypos",                    "7"                     },
-  { "emc_gate_7_gray.frames",                  "1"                     },
-  { "emc_gate_7_gray.EDITOR",                  "RocksEMC.png"          },
-  { "emc_gate_7_gray.EDITOR.xpos",             "2"                     },
-  { "emc_gate_7_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_7_gray.active",                  "RocksEMC.png"          },
-  { "emc_gate_7_gray.active.xpos",             "2"                     },
-  { "emc_gate_7_gray.active.ypos",             "6"                     },
-  { "emc_gate_7_gray.active.frames",           "1"                     },
-  { "emc_gate_8_gray",                         "RocksEMC.png"          },
-  { "emc_gate_8_gray.xpos",                    "4"                     },
-  { "emc_gate_8_gray.ypos",                    "7"                     },
-  { "emc_gate_8_gray.frames",                  "1"                     },
-  { "emc_gate_8_gray.EDITOR",                  "RocksEMC.png"          },
-  { "emc_gate_8_gray.EDITOR.xpos",             "3"                     },
-  { "emc_gate_8_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_8_gray.active",                  "RocksEMC.png"          },
-  { "emc_gate_8_gray.active.xpos",             "3"                     },
-  { "emc_gate_8_gray.active.ypos",             "6"                     },
-  { "emc_gate_8_gray.active.frames",           "1"                     },
-
-  { "emc_android",                             "RocksEMC.png"          },
-  { "emc_android.xpos",                                "0"                     },
-  { "emc_android.ypos",                                "8"                     },
-  { "emc_android.frames",                      "8"                     },
-  { "emc_android.delay",                       "2"                     },
-
-  { "emc_android.shrinking.upleft",            "RocksEMC.png"          },
-  { "emc_android.shrinking.upleft.xpos",       "1"                     },
-  { "emc_android.shrinking.upleft.ypos",       "11"                    },
-  { "emc_android.shrinking.upleft.frames",     "8"                     },
-  { "emc_android.shrinking.upleft.anim_mode",  "linear"                },
-
-  { "emc_android.growing.downright",           "RocksEMC.png"          },
-  { "emc_android.growing.downright.xpos",      "0"                     },
-  { "emc_android.growing.downright.ypos",      "11"                    },
-  { "emc_android.growing.downright.frames",    "8"                     },
-  { "emc_android.growing.downright.anim_mode", "linear,reverse"        },
-
-  { "emc_android.shrinking.downleft",          "RocksEMC.png"          },
-  { "emc_android.shrinking.downleft.xpos",     "1"                     },
-  { "emc_android.shrinking.downleft.ypos",     "12"                    },
-  { "emc_android.shrinking.downleft.frames",   "8"                     },
-  { "emc_android.shrinking.downleft.anim_mode",        "linear"                },
-
-  { "emc_android.growing.upright",             "RocksEMC.png"          },
-  { "emc_android.growing.upright.xpos",                "0"                     },
-  { "emc_android.growing.upright.ypos",                "12"                    },
-  { "emc_android.growing.upright.frames",      "8"                     },
-  { "emc_android.growing.upright.anim_mode",   "linear,reverse"        },
-
-  { "emc_android.shrinking.upright",           "RocksEMC.png"          },
-  { "emc_android.shrinking.upright.xpos",      "1"                     },
-  { "emc_android.shrinking.upright.ypos",      "13"                    },
-  { "emc_android.shrinking.upright.frames",    "8"                     },
-  { "emc_android.shrinking.upright.anim_mode", "linear"                },
-
-  { "emc_android.growing.downleft",            "RocksEMC.png"          },
-  { "emc_android.growing.downleft.xpos",       "0"                     },
-  { "emc_android.growing.downleft.ypos",       "13"                    },
-  { "emc_android.growing.downleft.frames",     "8"                     },
-  { "emc_android.growing.downleft.anim_mode",  "linear,reverse"        },
-
-  { "emc_android.shrinking.downright",         "RocksEMC.png"          },
-  { "emc_android.shrinking.downright.xpos",    "1"                     },
-  { "emc_android.shrinking.downright.ypos",    "14"                    },
-  { "emc_android.shrinking.downright.frames",  "8"                     },
-  { "emc_android.shrinking.downright.anim_mode","linear"               },
-
-  { "emc_android.growing.upleft",              "RocksEMC.png"          },
-  { "emc_android.growing.upleft.xpos",         "0"                     },
-  { "emc_android.growing.upleft.ypos",         "14"                    },
-  { "emc_android.growing.upleft.frames",       "8"                     },
-  { "emc_android.growing.upleft.anim_mode",    "linear,reverse"        },
-
-  { "emc_grass",                               "RocksEMC.png"          },
-  { "emc_grass.xpos",                          "0"                     },
-  { "emc_grass.ypos",                          "4"                     },
-  { "emc_grass.frames",                                "1"                     },
-  { "emc_grass.CRUMBLED",                      "RocksEMC.png"          },
-  { "emc_grass.CRUMBLED.xpos",                 "1"                     },
-  { "emc_grass.CRUMBLED.ypos",                 "4"                     },
-  { "emc_grass.CRUMBLED.frames",               "1"                     },
-  { "emc_grass.digging.left",                  "RocksEMC.png"          },
-  { "emc_grass.digging.left.xpos",             "6"                     },
-  { "emc_grass.digging.left.ypos",             "0"                     },
-  { "emc_grass.digging.left.frames",           "3"                     },
-  { "emc_grass.digging.left.delay",            "2"                     },
-  { "emc_grass.digging.left.anim_mode",                "linear"                },
-  { "emc_grass.digging.right",                 "RocksEMC.png"          },
-  { "emc_grass.digging.right.xpos",            "9"                     },
-  { "emc_grass.digging.right.ypos",            "0"                     },
-  { "emc_grass.digging.right.frames",          "3"                     },
-  { "emc_grass.digging.right.delay",           "2"                     },
-  { "emc_grass.digging.right.anim_mode",       "linear"                },
-  { "emc_grass.digging.up",                    "RocksEMC.png"          },
-  { "emc_grass.digging.up.xpos",               "0"                     },
-  { "emc_grass.digging.up.ypos",               "0"                     },
-  { "emc_grass.digging.up.frames",             "3"                     },
-  { "emc_grass.digging.up.delay",              "2"                     },
-  { "emc_grass.digging.up.anim_mode",          "linear"                },
-  { "emc_grass.digging.down",                  "RocksEMC.png"          },
-  { "emc_grass.digging.down.xpos",             "3"                     },
-  { "emc_grass.digging.down.ypos",             "0"                     },
-  { "emc_grass.digging.down.frames",           "3"                     },
-  { "emc_grass.digging.down.delay",            "2"                     },
-  { "emc_grass.digging.down.anim_mode",                "linear"                },
-  { "emc_grass.digging.left.CRUMBLED",         "RocksEMC.png"          },
-  { "emc_grass.digging.left.CRUMBLED.xpos",    "6"                     },
-  { "emc_grass.digging.left.CRUMBLED.ypos",    "1"                     },
-  { "emc_grass.digging.left.CRUMBLED.frames",  "3"                     },
-  { "emc_grass.digging.left.CRUMBLED.delay",   "2"                     },
-  { "emc_grass.digging.left.CRUMBLED.anim_mode","linear"               },
-  { "emc_grass.digging.right.CRUMBLED",                "RocksEMC.png"          },
-  { "emc_grass.digging.right.CRUMBLED.xpos",   "9"                     },
-  { "emc_grass.digging.right.CRUMBLED.ypos",   "1"                     },
-  { "emc_grass.digging.right.CRUMBLED.frames", "3"                     },
-  { "emc_grass.digging.right.CRUMBLED.delay",  "2"                     },
-  { "emc_grass.digging.right.CRUMBLED.anim_mode","linear"              },
-  { "emc_grass.digging.up.CRUMBLED",           "RocksEMC.png"          },
-  { "emc_grass.digging.up.CRUMBLED.xpos",      "0"                     },
-  { "emc_grass.digging.up.CRUMBLED.ypos",      "1"                     },
-  { "emc_grass.digging.up.CRUMBLED.frames",    "3"                     },
-  { "emc_grass.digging.up.CRUMBLED.delay",     "2"                     },
-  { "emc_grass.digging.up.CRUMBLED.anim_mode", "linear"                },
-  { "emc_grass.digging.down.CRUMBLED",         "RocksEMC.png"          },
-  { "emc_grass.digging.down.CRUMBLED.xpos",    "3"                     },
-  { "emc_grass.digging.down.CRUMBLED.ypos",    "1"                     },
-  { "emc_grass.digging.down.CRUMBLED.frames",  "3"                     },
-  { "emc_grass.digging.down.CRUMBLED.delay",   "2"                     },
-  { "emc_grass.digging.down.CRUMBLED.anim_mode","linear"               },
-
-  { "emc_magic_ball",                          "RocksEMC.png"          },
-  { "emc_magic_ball.xpos",                     "0"                     },
-  { "emc_magic_ball.ypos",                     "9"                     },
-  { "emc_magic_ball.frames",                   "1"                     },
-  { "emc_magic_ball.active",                   "RocksEMC.png"          },
-  { "emc_magic_ball.active.xpos",              "0"                     },
-  { "emc_magic_ball.active.ypos",              "9"                     },
-  { "emc_magic_ball.active.frames",            "16"                    },
-  { "emc_magic_ball.active.frames_per_line",   "8"                     },
-  { "emc_magic_ball.dropping",                 "RocksElements.png"     },
-  { "emc_magic_ball.dropping.xpos",            "0"                     },
-  { "emc_magic_ball.dropping.ypos",            "4"                     },
-  { "emc_magic_ball.dropping.frames",          "8"                     },
-  { "emc_magic_ball.dropping.anim_mode",       "linear"                },
-
-  { "emc_magic_ball_switch",                   "RocksEMC.png"          },
-  { "emc_magic_ball_switch.xpos",              "8"                     },
-  { "emc_magic_ball_switch.ypos",              "10"                    },
-  { "emc_magic_ball_switch.frames",            "1"                     },
-  { "emc_magic_ball_switch.active",            "RocksEMC.png"          },
-  { "emc_magic_ball_switch.active.xpos",       "8"                     },
-  { "emc_magic_ball_switch.active.ypos",       "9"                     },
-  { "emc_magic_ball_switch.active.frames",     "1"                     },
-
-  { "emc_spring_bumper",                       "RocksEMC.png"          },
-  { "emc_spring_bumper.xpos",                  "8"                     },
-  { "emc_spring_bumper.ypos",                  "4"                     },
-  { "emc_spring_bumper.frames",                        "1"                     },
-
-  { "emc_spring_bumper.active",                        "RocksEMC.png"          },
-  { "emc_spring_bumper.active.xpos",           "8"                     },
-  { "emc_spring_bumper.active.ypos",           "4"                     },
-  { "emc_spring_bumper.active.frames",         "4"                     },
-  { "emc_spring_bumper.active.anim_mode",      "pingpong2"             },
-
-  { "emc_plant",                               "RocksEMC.png"          },
-  { "emc_plant.xpos",                          "4"                     },
-  { "emc_plant.ypos",                          "4"                     },
-  { "emc_plant.frames",                                "1"                     },
-  { "emc_plant.CRUMBLED",                      "RocksEMC.png"          },
-  { "emc_plant.CRUMBLED.xpos",                 "5"                     },
-  { "emc_plant.CRUMBLED.ypos",                 "4"                     },
-  { "emc_plant.CRUMBLED.frames",               "1"                     },
-
-  { "emc_lenses",                              "RocksEMC.png"          },
-  { "emc_lenses.xpos",                         "6"                     },
-  { "emc_lenses.ypos",                         "4"                     },
-  { "emc_lenses.frames",                       "1"                     },
-  { "emc_lenses.collecting",                   "RocksCollect.png"      },
-  { "emc_lenses.collecting.xpos",              "7"                     },
-  { "emc_lenses.collecting.ypos",              "16"                    },
-  { "emc_lenses.collecting.frames",            "7"                     },
-  { "emc_lenses.collecting.anim_mode",         "linear"                },
-
-  { "emc_magnifier",                           "RocksEMC.png"          },
-  { "emc_magnifier.xpos",                      "7"                     },
-  { "emc_magnifier.ypos",                      "4"                     },
-  { "emc_magnifier.frames",                    "1"                     },
-  { "emc_magnifier.collecting",                        "RocksCollect.png"      },
-  { "emc_magnifier.collecting.xpos",           "7"                     },
-  { "emc_magnifier.collecting.ypos",           "17"                    },
-  { "emc_magnifier.collecting.frames",         "7"                     },
-  { "emc_magnifier.collecting.anim_mode",      "linear"                },
-
-  { "emc_wall_9",                              "RocksEMC.png"          },
-  { "emc_wall_9.xpos",                         "10"                    },
-  { "emc_wall_9.ypos",                         "5"                     },
-  { "emc_wall_9.frames",                       "1"                     },
-  { "emc_wall_10",                             "RocksEMC.png"          },
-  { "emc_wall_10.xpos",                                "10"                    },
-  { "emc_wall_10.ypos",                                "6"                     },
-  { "emc_wall_10.frames",                      "1"                     },
-  { "emc_wall_11",                             "RocksEMC.png"          },
-  { "emc_wall_11.xpos",                                "11"                    },
-  { "emc_wall_11.ypos",                                "5"                     },
-  { "emc_wall_11.frames",                      "1"                     },
-  { "emc_wall_12",                             "RocksEMC.png"          },
-  { "emc_wall_12.xpos",                                "11"                    },
-  { "emc_wall_12.ypos",                                "6"                     },
-  { "emc_wall_12.frames",                      "1"                     },
-  { "emc_wall_13",                             "RocksEMC.png"          },
-  { "emc_wall_13.xpos",                                "10"                    },
-  { "emc_wall_13.ypos",                                "7"                     },
-  { "emc_wall_13.frames",                      "1"                     },
-  { "emc_wall_14",                             "RocksEMC.png"          },
-  { "emc_wall_14.xpos",                                "10"                    },
-  { "emc_wall_14.ypos",                                "8"                     },
-  { "emc_wall_14.frames",                      "1"                     },
-  { "emc_wall_15",                             "RocksEMC.png"          },
-  { "emc_wall_15.xpos",                                "10"                    },
-  { "emc_wall_15.ypos",                                "9"                     },
-  { "emc_wall_15.frames",                      "1"                     },
-  { "emc_wall_16",                             "RocksEMC.png"          },
-  { "emc_wall_16.xpos",                                "10"                    },
-  { "emc_wall_16.ypos",                                "10"                    },
-  { "emc_wall_16.frames",                      "1"                     },
-
-  { "emc_wall_slippery_1",                     "RocksEMC.png"          },
-  { "emc_wall_slippery_1.xpos",                        "11"                    },
-  { "emc_wall_slippery_1.ypos",                        "7"                     },
-  { "emc_wall_slippery_1.frames",              "1"                     },
-  { "emc_wall_slippery_2",                     "RocksEMC.png"          },
-  { "emc_wall_slippery_2.xpos",                        "11"                    },
-  { "emc_wall_slippery_2.ypos",                        "8"                     },
-  { "emc_wall_slippery_2.frames",              "1"                     },
-  { "emc_wall_slippery_3",                     "RocksEMC.png"          },
-  { "emc_wall_slippery_3.xpos",                        "11"                    },
-  { "emc_wall_slippery_3.ypos",                        "9"                     },
-  { "emc_wall_slippery_3.frames",              "1"                     },
-  { "emc_wall_slippery_4",                     "RocksEMC.png"          },
-  { "emc_wall_slippery_4.xpos",                        "11"                    },
-  { "emc_wall_slippery_4.ypos",                        "10"                    },
-  { "emc_wall_slippery_4.frames",              "1"                     },
-
-  { "emc_fake_grass",                          "RocksEMC.png"          },
-  { "emc_fake_grass.xpos",                     "0"                     },
-  { "emc_fake_grass.ypos",                     "4"                     },
-  { "emc_fake_grass.frames",                   "1"                     },
-  { "emc_fake_grass.CRUMBLED",                 "RocksEMC.png"          },
-  { "emc_fake_grass.CRUMBLED.xpos",            "1"                     },
-  { "emc_fake_grass.CRUMBLED.ypos",            "4"                     },
-  { "emc_fake_grass.CRUMBLED.frames",          "1"                     },
-  { "emc_fake_grass.active",                   "RocksEMC.png"          },
-  { "emc_fake_grass.active.xpos",              "2"                     },
-  { "emc_fake_grass.active.ypos",              "4"                     },
-  { "emc_fake_grass.active.frames",            "1"                     },
-  { "emc_fake_grass.active.CRUMBLED",          "RocksEMC.png"          },
-  { "emc_fake_grass.active.CRUMBLED.xpos",     "3"                     },
-  { "emc_fake_grass.active.CRUMBLED.ypos",     "4"                     },
-  { "emc_fake_grass.active.CRUMBLED.frames",   "1"                     },
-  { "emc_fake_grass.EDITOR",                   "RocksEMC.png"          },
-  { "emc_fake_grass.EDITOR.xpos",              "2"                     },
-  { "emc_fake_grass.EDITOR.ypos",              "4"                     },
-  { "emc_fake_grass.EDITOR.frames",            "1"                     },
-
-  { "emc_fake_acid",                           "RocksElements.png"     },
-  { "emc_fake_acid.xpos",                      "12"                    },
-  { "emc_fake_acid.ypos",                      "7"                     },
-  { "emc_fake_acid.frames",                    "4"                     },
-  { "emc_fake_acid.delay",                     "10"                    },
-  { "emc_fake_acid.global_sync",               "true"                  },
-
-  { "emc_dripper",                             "RocksSP.png"           },
-  { "emc_dripper.xpos",                                "0"                     },
-  { "emc_dripper.ypos",                                "0"                     },
-  { "emc_dripper.frames",                      "1"                     },
-  { "emc_dripper.EDITOR",                      "RocksEMC.png"          },
-  { "emc_dripper.EDITOR.xpos",                 "8"                     },
-  { "emc_dripper.EDITOR.ypos",                 "8"                     },
-  { "emc_dripper.active",                      "RocksEMC.png"          },
-  { "emc_dripper.active.xpos",                 "8"                     },
-  { "emc_dripper.active.ypos",                 "8"                     },
-  { "emc_dripper.active.frames",               "1"                     },
-
-  { "mm_mcduffin",                             "RocksMM.png"           },
-  { "mm_mcduffin.xpos",                                "4"                     },
-  { "mm_mcduffin.ypos",                                "1"                     },
-  { "mm_mcduffin.frames",                      "4"                     },
-  { "mm_mcduffin.delay",                       "8"                     },
-  { "mm_mcduffin.right",                       "RocksMM.png"           },
-  { "mm_mcduffin.right.xpos",                  "4"                     },
-  { "mm_mcduffin.right.ypos",                  "1"                     },
-  { "mm_mcduffin.right.frames",                        "1"                     },
-  { "mm_mcduffin.up",                          "RocksMM.png"           },
-  { "mm_mcduffin.up.xpos",                     "5"                     },
-  { "mm_mcduffin.up.ypos",                     "1"                     },
-  { "mm_mcduffin.up.frames",                   "1"                     },
-  { "mm_mcduffin.left",                                "RocksMM.png"           },
-  { "mm_mcduffin.left.xpos",                   "6"                     },
-  { "mm_mcduffin.left.ypos",                   "1"                     },
-  { "mm_mcduffin.left.frames",                 "1"                     },
-  { "mm_mcduffin.down",                                "RocksMM.png"           },
-  { "mm_mcduffin.down.xpos",                   "7"                     },
-  { "mm_mcduffin.down.ypos",                   "1"                     },
-  { "mm_mcduffin.down.frames",                 "1"                     },
-
-  { "mm_exit_closed",                          "RocksMM.png"           },
-  { "mm_exit_closed.xpos",                     "8"                     },
-  { "mm_exit_closed.ypos",                     "1"                     },
-  { "mm_exit_closed.frames",                   "1"                     },
-  { "mm_exit.opening",                         "RocksMM.png"           },
-  { "mm_exit.opening.xpos",                    "8"                     },
-  { "mm_exit.opening.ypos",                    "1"                     },
-  { "mm_exit.opening.frames",                  "4"                     },
-  { "mm_exit.opening.delay",                   "6"                     },
-  { "mm_exit.opening.anim_mode",               "linear"                },
-  { "mm_exit_open",                            "RocksMM.png"           },
-  { "mm_exit_open.xpos",                       "11"                    },
-  { "mm_exit_open.ypos",                       "1"                     },
-  { "mm_exit_open.frames",                     "1"                     },
-  { "mm_exit.closing",                         "RocksMM.png"           },
-  { "mm_exit.closing.xpos",                    "8"                     },
-  { "mm_exit.closing.ypos",                    "1"                     },
-  { "mm_exit.closing.frames",                  "4"                     },
-  { "mm_exit.closing.delay",                   "6"                     },
-  { "mm_exit.closing.anim_mode",               "linear,reverse"        },
-
-  { "mm_mirror_1",                             "RocksMM.png"           },
-  { "mm_mirror_1.xpos",                                "0"                     },
-  { "mm_mirror_1.ypos",                                "0"                     },
-  { "mm_mirror_1.frames",                      "1"                     },
-  { "mm_mirror_2",                             "RocksMM.png"           },
-  { "mm_mirror_2.xpos",                                "1"                     },
-  { "mm_mirror_2.ypos",                                "0"                     },
-  { "mm_mirror_2.frames",                      "1"                     },
-  { "mm_mirror_3",                             "RocksMM.png"           },
-  { "mm_mirror_3.xpos",                                "2"                     },
-  { "mm_mirror_3.ypos",                                "0"                     },
-  { "mm_mirror_3.frames",                      "1"                     },
-  { "mm_mirror_4",                             "RocksMM.png"           },
-  { "mm_mirror_4.xpos",                                "3"                     },
-  { "mm_mirror_4.ypos",                                "0"                     },
-  { "mm_mirror_4.frames",                      "1"                     },
-  { "mm_mirror_5",                             "RocksMM.png"           },
-  { "mm_mirror_5.xpos",                                "4"                     },
-  { "mm_mirror_5.ypos",                                "0"                     },
-  { "mm_mirror_5.frames",                      "1"                     },
-  { "mm_mirror_6",                             "RocksMM.png"           },
-  { "mm_mirror_6.xpos",                                "5"                     },
-  { "mm_mirror_6.ypos",                                "0"                     },
-  { "mm_mirror_6.frames",                      "1"                     },
-  { "mm_mirror_7",                             "RocksMM.png"           },
-  { "mm_mirror_7.xpos",                                "6"                     },
-  { "mm_mirror_7.ypos",                                "0"                     },
-  { "mm_mirror_7.frames",                      "1"                     },
-  { "mm_mirror_8",                             "RocksMM.png"           },
-  { "mm_mirror_8.xpos",                                "7"                     },
-  { "mm_mirror_8.ypos",                                "0"                     },
-  { "mm_mirror_8.frames",                      "1"                     },
-  { "mm_mirror_9",                             "RocksMM.png"           },
-  { "mm_mirror_9.xpos",                                "8"                     },
-  { "mm_mirror_9.ypos",                                "0"                     },
-  { "mm_mirror_9.frames",                      "1"                     },
-  { "mm_mirror_10",                            "RocksMM.png"           },
-  { "mm_mirror_10.xpos",                       "9"                     },
-  { "mm_mirror_10.ypos",                       "0"                     },
-  { "mm_mirror_10.frames",                     "1"                     },
-  { "mm_mirror_11",                            "RocksMM.png"           },
-  { "mm_mirror_11.xpos",                       "10"                    },
-  { "mm_mirror_11.ypos",                       "0"                     },
-  { "mm_mirror_11.frames",                     "1"                     },
-  { "mm_mirror_12",                            "RocksMM.png"           },
-  { "mm_mirror_12.xpos",                       "11"                    },
-  { "mm_mirror_12.ypos",                       "0"                     },
-  { "mm_mirror_12.frames",                     "1"                     },
-  { "mm_mirror_13",                            "RocksMM.png"           },
-  { "mm_mirror_13.xpos",                       "12"                    },
-  { "mm_mirror_13.ypos",                       "0"                     },
-  { "mm_mirror_13.frames",                     "1"                     },
-  { "mm_mirror_14",                            "RocksMM.png"           },
-  { "mm_mirror_14.xpos",                       "13"                    },
-  { "mm_mirror_14.ypos",                       "0"                     },
-  { "mm_mirror_14.frames",                     "1"                     },
-  { "mm_mirror_15",                            "RocksMM.png"           },
-  { "mm_mirror_15.xpos",                       "14"                    },
-  { "mm_mirror_15.ypos",                       "0"                     },
-  { "mm_mirror_15.frames",                     "1"                     },
-  { "mm_mirror_16",                            "RocksMM.png"           },
-  { "mm_mirror_16.xpos",                       "15"                    },
-  { "mm_mirror_16.ypos",                       "0"                     },
-  { "mm_mirror_16.frames",                     "1"                     },
-
-  { "mm_mirror_fixed_1",                       "RocksMM.png"           },
-  { "mm_mirror_fixed_1.xpos",                  "4"                     },
-  { "mm_mirror_fixed_1.ypos",                  "6"                     },
-  { "mm_mirror_fixed_1.frames",                        "1"                     },
-  { "mm_mirror_fixed_2",                       "RocksMM.png"           },
-  { "mm_mirror_fixed_2.xpos",                  "5"                     },
-  { "mm_mirror_fixed_2.ypos",                  "6"                     },
-  { "mm_mirror_fixed_2.frames",                        "1"                     },
-  { "mm_mirror_fixed_3",                       "RocksMM.png"           },
-  { "mm_mirror_fixed_3.xpos",                  "6"                     },
-  { "mm_mirror_fixed_3.ypos",                  "6"                     },
-  { "mm_mirror_fixed_3.frames",                        "1"                     },
-  { "mm_mirror_fixed_4",                       "RocksMM.png"           },
-  { "mm_mirror_fixed_4.xpos",                  "7"                     },
-  { "mm_mirror_fixed_4.ypos",                  "6"                     },
-  { "mm_mirror_fixed_4.frames",                        "1"                     },
-
-  { "mm_steel_grid_fixed_1",                   "RocksMM.png"           },
-  { "mm_steel_grid_fixed_1.xpos",              "0"                     },
-  { "mm_steel_grid_fixed_1.ypos",              "1"                     },
-  { "mm_steel_grid_fixed_1.frames",            "1"                     },
-  { "mm_steel_grid_fixed_2",                   "RocksMM.png"           },
-  { "mm_steel_grid_fixed_2.xpos",              "1"                     },
-  { "mm_steel_grid_fixed_2.ypos",              "1"                     },
-  { "mm_steel_grid_fixed_2.frames",            "1"                     },
-  { "mm_steel_grid_fixed_3",                   "RocksMM.png"           },
-  { "mm_steel_grid_fixed_3.xpos",              "2"                     },
-  { "mm_steel_grid_fixed_3.ypos",              "1"                     },
-  { "mm_steel_grid_fixed_3.frames",            "1"                     },
-  { "mm_steel_grid_fixed_4",                   "RocksMM.png"           },
-  { "mm_steel_grid_fixed_4.xpos",              "3"                     },
-  { "mm_steel_grid_fixed_4.ypos",              "1"                     },
-  { "mm_steel_grid_fixed_4.frames",            "1"                     },
-
-  { "mm_wooden_grid_fixed_1",                  "RocksMM.png"           },
-  { "mm_wooden_grid_fixed_1.xpos",             "12"                    },
-  { "mm_wooden_grid_fixed_1.ypos",             "6"                     },
-  { "mm_wooden_grid_fixed_1.frames",           "1"                     },
-  { "mm_wooden_grid_fixed_2",                  "RocksMM.png"           },
-  { "mm_wooden_grid_fixed_2.xpos",             "13"                    },
-  { "mm_wooden_grid_fixed_2.ypos",             "6"                     },
-  { "mm_wooden_grid_fixed_2.frames",           "1"                     },
-  { "mm_wooden_grid_fixed_3",                  "RocksMM.png"           },
-  { "mm_wooden_grid_fixed_3.xpos",             "14"                    },
-  { "mm_wooden_grid_fixed_3.ypos",             "6"                     },
-  { "mm_wooden_grid_fixed_3.frames",           "1"                     },
-  { "mm_wooden_grid_fixed_4",                  "RocksMM.png"           },
-  { "mm_wooden_grid_fixed_4.xpos",             "15"                    },
-  { "mm_wooden_grid_fixed_4.ypos",             "6"                     },
-  { "mm_wooden_grid_fixed_4.frames",           "1"                     },
-
-  { "mm_polarizer_1",                          "RocksMM.png"           },
-  { "mm_polarizer_1.xpos",                     "0"                     },
-  { "mm_polarizer_1.ypos",                     "5"                     },
-  { "mm_polarizer_1.frames",                   "1"                     },
-  { "mm_polarizer_2",                          "RocksMM.png"           },
-  { "mm_polarizer_2.xpos",                     "1"                     },
-  { "mm_polarizer_2.ypos",                     "5"                     },
-  { "mm_polarizer_2.frames",                   "1"                     },
-  { "mm_polarizer_3",                          "RocksMM.png"           },
-  { "mm_polarizer_3.xpos",                     "2"                     },
-  { "mm_polarizer_3.ypos",                     "5"                     },
-  { "mm_polarizer_3.frames",                   "1"                     },
-  { "mm_polarizer_4",                          "RocksMM.png"           },
-  { "mm_polarizer_4.xpos",                     "3"                     },
-  { "mm_polarizer_4.ypos",                     "5"                     },
-  { "mm_polarizer_4.frames",                   "1"                     },
-  { "mm_polarizer_5",                          "RocksMM.png"           },
-  { "mm_polarizer_5.xpos",                     "4"                     },
-  { "mm_polarizer_5.ypos",                     "5"                     },
-  { "mm_polarizer_5.frames",                   "1"                     },
-  { "mm_polarizer_6",                          "RocksMM.png"           },
-  { "mm_polarizer_6.xpos",                     "5"                     },
-  { "mm_polarizer_6.ypos",                     "5"                     },
-  { "mm_polarizer_6.frames",                   "1"                     },
-  { "mm_polarizer_7",                          "RocksMM.png"           },
-  { "mm_polarizer_7.xpos",                     "6"                     },
-  { "mm_polarizer_7.ypos",                     "5"                     },
-  { "mm_polarizer_7.frames",                   "1"                     },
-  { "mm_polarizer_8",                          "RocksMM.png"           },
-  { "mm_polarizer_8.xpos",                     "7"                     },
-  { "mm_polarizer_8.ypos",                     "5"                     },
-  { "mm_polarizer_8.frames",                   "1"                     },
-  { "mm_polarizer_9",                          "RocksMM.png"           },
-  { "mm_polarizer_9.xpos",                     "8"                     },
-  { "mm_polarizer_9.ypos",                     "5"                     },
-  { "mm_polarizer_9.frames",                   "1"                     },
-  { "mm_polarizer_10",                         "RocksMM.png"           },
-  { "mm_polarizer_10.xpos",                    "9"                     },
-  { "mm_polarizer_10.ypos",                    "5"                     },
-  { "mm_polarizer_10.frames",                  "1"                     },
-  { "mm_polarizer_11",                         "RocksMM.png"           },
-  { "mm_polarizer_11.xpos",                    "10"                    },
-  { "mm_polarizer_11.ypos",                    "5"                     },
-  { "mm_polarizer_11.frames",                  "1"                     },
-  { "mm_polarizer_12",                         "RocksMM.png"           },
-  { "mm_polarizer_12.xpos",                    "11"                    },
-  { "mm_polarizer_12.ypos",                    "5"                     },
-  { "mm_polarizer_12.frames",                  "1"                     },
-  { "mm_polarizer_13",                         "RocksMM.png"           },
-  { "mm_polarizer_13.xpos",                    "12"                    },
-  { "mm_polarizer_13.ypos",                    "5"                     },
-  { "mm_polarizer_13.frames",                  "1"                     },
-  { "mm_polarizer_14",                         "RocksMM.png"           },
-  { "mm_polarizer_14.xpos",                    "13"                    },
-  { "mm_polarizer_14.ypos",                    "5"                     },
-  { "mm_polarizer_14.frames",                  "1"                     },
-  { "mm_polarizer_15",                         "RocksMM.png"           },
-  { "mm_polarizer_15.xpos",                    "14"                    },
-  { "mm_polarizer_15.ypos",                    "5"                     },
-  { "mm_polarizer_15.frames",                  "1"                     },
-  { "mm_polarizer_16",                         "RocksMM.png"           },
-  { "mm_polarizer_16.xpos",                    "15"                    },
-  { "mm_polarizer_16.ypos",                    "5"                     },
-  { "mm_polarizer_16.frames",                  "1"                     },
-
-  { "mm_polarizer_cross_1",                    "RocksMM.png"           },
-  { "mm_polarizer_cross_1.xpos",               "0"                     },
-  { "mm_polarizer_cross_1.ypos",               "6"                     },
-  { "mm_polarizer_cross_1.frames",             "1"                     },
-  { "mm_polarizer_cross_2",                    "RocksMM.png"           },
-  { "mm_polarizer_cross_2.xpos",               "1"                     },
-  { "mm_polarizer_cross_2.ypos",               "6"                     },
-  { "mm_polarizer_cross_2.frames",             "1"                     },
-  { "mm_polarizer_cross_3",                    "RocksMM.png"           },
-  { "mm_polarizer_cross_3.xpos",               "2"                     },
-  { "mm_polarizer_cross_3.ypos",               "6"                     },
-  { "mm_polarizer_cross_3.frames",             "1"                     },
-  { "mm_polarizer_cross_4",                    "RocksMM.png"           },
-  { "mm_polarizer_cross_4.xpos",               "3"                     },
-  { "mm_polarizer_cross_4.ypos",               "6"                     },
-  { "mm_polarizer_cross_4.frames",             "1"                     },
-
-  { "mm_teleporter_1",                         "RocksMM.png"           },
-  { "mm_teleporter_1.xpos",                    "0"                     },
-  { "mm_teleporter_1.ypos",                    "3"                     },
-  { "mm_teleporter_1.frames",                  "1"                     },
-  { "mm_teleporter_2",                         "RocksMM.png"           },
-  { "mm_teleporter_2.xpos",                    "1"                     },
-  { "mm_teleporter_2.ypos",                    "3"                     },
-  { "mm_teleporter_2.frames",                  "1"                     },
-  { "mm_teleporter_3",                         "RocksMM.png"           },
-  { "mm_teleporter_3.xpos",                    "2"                     },
-  { "mm_teleporter_3.ypos",                    "3"                     },
-  { "mm_teleporter_3.frames",                  "1"                     },
-  { "mm_teleporter_4",                         "RocksMM.png"           },
-  { "mm_teleporter_4.xpos",                    "3"                     },
-  { "mm_teleporter_4.ypos",                    "3"                     },
-  { "mm_teleporter_4.frames",                  "1"                     },
-  { "mm_teleporter_5",                         "RocksMM.png"           },
-  { "mm_teleporter_5.xpos",                    "4"                     },
-  { "mm_teleporter_5.ypos",                    "3"                     },
-  { "mm_teleporter_5.frames",                  "1"                     },
-  { "mm_teleporter_6",                         "RocksMM.png"           },
-  { "mm_teleporter_6.xpos",                    "5"                     },
-  { "mm_teleporter_6.ypos",                    "3"                     },
-  { "mm_teleporter_6.frames",                  "1"                     },
-  { "mm_teleporter_7",                         "RocksMM.png"           },
-  { "mm_teleporter_7.xpos",                    "6"                     },
-  { "mm_teleporter_7.ypos",                    "3"                     },
-  { "mm_teleporter_7.frames",                  "1"                     },
-  { "mm_teleporter_8",                         "RocksMM.png"           },
-  { "mm_teleporter_8.xpos",                    "7"                     },
-  { "mm_teleporter_8.ypos",                    "3"                     },
-  { "mm_teleporter_8.frames",                  "1"                     },
-  { "mm_teleporter_9",                         "RocksMM.png"           },
-  { "mm_teleporter_9.xpos",                    "8"                     },
-  { "mm_teleporter_9.ypos",                    "3"                     },
-  { "mm_teleporter_9.frames",                  "1"                     },
-  { "mm_teleporter_10",                                "RocksMM.png"           },
-  { "mm_teleporter_10.xpos",                   "9"                     },
-  { "mm_teleporter_10.ypos",                   "3"                     },
-  { "mm_teleporter_10.frames",                 "1"                     },
-  { "mm_teleporter_11",                                "RocksMM.png"           },
-  { "mm_teleporter_11.xpos",                   "10"                    },
-  { "mm_teleporter_11.ypos",                   "3"                     },
-  { "mm_teleporter_11.frames",                 "1"                     },
-  { "mm_teleporter_12",                                "RocksMM.png"           },
-  { "mm_teleporter_12.xpos",                   "11"                    },
-  { "mm_teleporter_12.ypos",                   "3"                     },
-  { "mm_teleporter_12.frames",                 "1"                     },
-  { "mm_teleporter_13",                                "RocksMM.png"           },
-  { "mm_teleporter_13.xpos",                   "12"                    },
-  { "mm_teleporter_13.ypos",                   "3"                     },
-  { "mm_teleporter_13.frames",                 "1"                     },
-  { "mm_teleporter_14",                                "RocksMM.png"           },
-  { "mm_teleporter_14.xpos",                   "13"                    },
-  { "mm_teleporter_14.ypos",                   "3"                     },
-  { "mm_teleporter_14.frames",                 "1"                     },
-  { "mm_teleporter_15",                                "RocksMM.png"           },
-  { "mm_teleporter_15.xpos",                   "14"                    },
-  { "mm_teleporter_15.ypos",                   "3"                     },
-  { "mm_teleporter_15.frames",                 "1"                     },
-  { "mm_teleporter_16",                                "RocksMM.png"           },
-  { "mm_teleporter_16.xpos",                   "15"                    },
-  { "mm_teleporter_16.ypos",                   "3"                     },
-  { "mm_teleporter_16.frames",                 "1"                     },
-
-  { "mm_teleporter_red_1",                     "RocksDF.png"           },
-  { "mm_teleporter_red_1.xpos",                        "0"                     },
-  { "mm_teleporter_red_1.ypos",                        "4"                     },
-  { "mm_teleporter_red_1.frames",              "1"                     },
-  { "mm_teleporter_red_2",                     "RocksDF.png"           },
-  { "mm_teleporter_red_2.xpos",                        "1"                     },
-  { "mm_teleporter_red_2.ypos",                        "4"                     },
-  { "mm_teleporter_red_2.frames",              "1"                     },
-  { "mm_teleporter_red_3",                     "RocksDF.png"           },
-  { "mm_teleporter_red_3.xpos",                        "2"                     },
-  { "mm_teleporter_red_3.ypos",                        "4"                     },
-  { "mm_teleporter_red_3.frames",              "1"                     },
-  { "mm_teleporter_red_4",                     "RocksDF.png"           },
-  { "mm_teleporter_red_4.xpos",                        "3"                     },
-  { "mm_teleporter_red_4.ypos",                        "4"                     },
-  { "mm_teleporter_red_4.frames",              "1"                     },
-  { "mm_teleporter_red_5",                     "RocksDF.png"           },
-  { "mm_teleporter_red_5.xpos",                        "4"                     },
-  { "mm_teleporter_red_5.ypos",                        "4"                     },
-  { "mm_teleporter_red_5.frames",              "1"                     },
-  { "mm_teleporter_red_6",                     "RocksDF.png"           },
-  { "mm_teleporter_red_6.xpos",                        "5"                     },
-  { "mm_teleporter_red_6.ypos",                        "4"                     },
-  { "mm_teleporter_red_6.frames",              "1"                     },
-  { "mm_teleporter_red_7",                     "RocksDF.png"           },
-  { "mm_teleporter_red_7.xpos",                        "6"                     },
-  { "mm_teleporter_red_7.ypos",                        "4"                     },
-  { "mm_teleporter_red_7.frames",              "1"                     },
-  { "mm_teleporter_red_8",                     "RocksDF.png"           },
-  { "mm_teleporter_red_8.xpos",                        "7"                     },
-  { "mm_teleporter_red_8.ypos",                        "4"                     },
-  { "mm_teleporter_red_8.frames",              "1"                     },
-  { "mm_teleporter_red_9",                     "RocksDF.png"           },
-  { "mm_teleporter_red_9.xpos",                        "8"                     },
-  { "mm_teleporter_red_9.ypos",                        "4"                     },
-  { "mm_teleporter_red_9.frames",              "1"                     },
-  { "mm_teleporter_red_10",                    "RocksDF.png"           },
-  { "mm_teleporter_red_10.xpos",               "9"                     },
-  { "mm_teleporter_red_10.ypos",               "4"                     },
-  { "mm_teleporter_red_10.frames",             "1"                     },
-  { "mm_teleporter_red_11",                    "RocksDF.png"           },
-  { "mm_teleporter_red_11.xpos",               "10"                    },
-  { "mm_teleporter_red_11.ypos",               "4"                     },
-  { "mm_teleporter_red_11.frames",             "1"                     },
-  { "mm_teleporter_red_12",                    "RocksDF.png"           },
-  { "mm_teleporter_red_12.xpos",               "11"                    },
-  { "mm_teleporter_red_12.ypos",               "4"                     },
-  { "mm_teleporter_red_12.frames",             "1"                     },
-  { "mm_teleporter_red_13",                    "RocksDF.png"           },
-  { "mm_teleporter_red_13.xpos",               "12"                    },
-  { "mm_teleporter_red_13.ypos",               "4"                     },
-  { "mm_teleporter_red_13.frames",             "1"                     },
-  { "mm_teleporter_red_14",                    "RocksDF.png"           },
-  { "mm_teleporter_red_14.xpos",               "13"                    },
-  { "mm_teleporter_red_14.ypos",               "4"                     },
-  { "mm_teleporter_red_14.frames",             "1"                     },
-  { "mm_teleporter_red_15",                    "RocksDF.png"           },
-  { "mm_teleporter_red_15.xpos",               "14"                    },
-  { "mm_teleporter_red_15.ypos",               "4"                     },
-  { "mm_teleporter_red_15.frames",             "1"                     },
-  { "mm_teleporter_red_16",                    "RocksDF.png"           },
-  { "mm_teleporter_red_16.xpos",               "15"                    },
-  { "mm_teleporter_red_16.ypos",               "4"                     },
-  { "mm_teleporter_red_16.frames",             "1"                     },
-
-  { "mm_teleporter_yellow_1",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_1.xpos",             "0"                     },
-  { "mm_teleporter_yellow_1.ypos",             "5"                     },
-  { "mm_teleporter_yellow_1.frames",           "1"                     },
-  { "mm_teleporter_yellow_2",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_2.xpos",             "1"                     },
-  { "mm_teleporter_yellow_2.ypos",             "5"                     },
-  { "mm_teleporter_yellow_2.frames",           "1"                     },
-  { "mm_teleporter_yellow_3",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_3.xpos",             "2"                     },
-  { "mm_teleporter_yellow_3.ypos",             "5"                     },
-  { "mm_teleporter_yellow_3.frames",           "1"                     },
-  { "mm_teleporter_yellow_4",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_4.xpos",             "3"                     },
-  { "mm_teleporter_yellow_4.ypos",             "5"                     },
-  { "mm_teleporter_yellow_4.frames",           "1"                     },
-  { "mm_teleporter_yellow_5",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_5.xpos",             "4"                     },
-  { "mm_teleporter_yellow_5.ypos",             "5"                     },
-  { "mm_teleporter_yellow_5.frames",           "1"                     },
-  { "mm_teleporter_yellow_6",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_6.xpos",             "5"                     },
-  { "mm_teleporter_yellow_6.ypos",             "5"                     },
-  { "mm_teleporter_yellow_6.frames",           "1"                     },
-  { "mm_teleporter_yellow_7",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_7.xpos",             "6"                     },
-  { "mm_teleporter_yellow_7.ypos",             "5"                     },
-  { "mm_teleporter_yellow_7.frames",           "1"                     },
-  { "mm_teleporter_yellow_8",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_8.xpos",             "7"                     },
-  { "mm_teleporter_yellow_8.ypos",             "5"                     },
-  { "mm_teleporter_yellow_8.frames",           "1"                     },
-  { "mm_teleporter_yellow_9",                  "RocksDF.png"           },
-  { "mm_teleporter_yellow_9.xpos",             "8"                     },
-  { "mm_teleporter_yellow_9.ypos",             "5"                     },
-  { "mm_teleporter_yellow_9.frames",           "1"                     },
-  { "mm_teleporter_yellow_10",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_10.xpos",            "9"                     },
-  { "mm_teleporter_yellow_10.ypos",            "5"                     },
-  { "mm_teleporter_yellow_10.frames",          "1"                     },
-  { "mm_teleporter_yellow_11",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_11.xpos",            "10"                    },
-  { "mm_teleporter_yellow_11.ypos",            "5"                     },
-  { "mm_teleporter_yellow_11.frames",          "1"                     },
-  { "mm_teleporter_yellow_12",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_12.xpos",            "11"                    },
-  { "mm_teleporter_yellow_12.ypos",            "5"                     },
-  { "mm_teleporter_yellow_12.frames",          "1"                     },
-  { "mm_teleporter_yellow_13",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_13.xpos",            "12"                    },
-  { "mm_teleporter_yellow_13.ypos",            "5"                     },
-  { "mm_teleporter_yellow_13.frames",          "1"                     },
-  { "mm_teleporter_yellow_14",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_14.xpos",            "13"                    },
-  { "mm_teleporter_yellow_14.ypos",            "5"                     },
-  { "mm_teleporter_yellow_14.frames",          "1"                     },
-  { "mm_teleporter_yellow_15",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_15.xpos",            "14"                    },
-  { "mm_teleporter_yellow_15.ypos",            "5"                     },
-  { "mm_teleporter_yellow_15.frames",          "1"                     },
-  { "mm_teleporter_yellow_16",                 "RocksDF.png"           },
-  { "mm_teleporter_yellow_16.xpos",            "15"                    },
-  { "mm_teleporter_yellow_16.ypos",            "5"                     },
-  { "mm_teleporter_yellow_16.frames",          "1"                     },
-
-  { "mm_teleporter_green_1",                   "RocksDF.png"           },
-  { "mm_teleporter_green_1.xpos",              "0"                     },
-  { "mm_teleporter_green_1.ypos",              "6"                     },
-  { "mm_teleporter_green_1.frames",            "1"                     },
-  { "mm_teleporter_green_2",                   "RocksDF.png"           },
-  { "mm_teleporter_green_2.xpos",              "1"                     },
-  { "mm_teleporter_green_2.ypos",              "6"                     },
-  { "mm_teleporter_green_2.frames",            "1"                     },
-  { "mm_teleporter_green_3",                   "RocksDF.png"           },
-  { "mm_teleporter_green_3.xpos",              "2"                     },
-  { "mm_teleporter_green_3.ypos",              "6"                     },
-  { "mm_teleporter_green_3.frames",            "1"                     },
-  { "mm_teleporter_green_4",                   "RocksDF.png"           },
-  { "mm_teleporter_green_4.xpos",              "3"                     },
-  { "mm_teleporter_green_4.ypos",              "6"                     },
-  { "mm_teleporter_green_4.frames",            "1"                     },
-  { "mm_teleporter_green_5",                   "RocksDF.png"           },
-  { "mm_teleporter_green_5.xpos",              "4"                     },
-  { "mm_teleporter_green_5.ypos",              "6"                     },
-  { "mm_teleporter_green_5.frames",            "1"                     },
-  { "mm_teleporter_green_6",                   "RocksDF.png"           },
-  { "mm_teleporter_green_6.xpos",              "5"                     },
-  { "mm_teleporter_green_6.ypos",              "6"                     },
-  { "mm_teleporter_green_6.frames",            "1"                     },
-  { "mm_teleporter_green_7",                   "RocksDF.png"           },
-  { "mm_teleporter_green_7.xpos",              "6"                     },
-  { "mm_teleporter_green_7.ypos",              "6"                     },
-  { "mm_teleporter_green_7.frames",            "1"                     },
-  { "mm_teleporter_green_8",                   "RocksDF.png"           },
-  { "mm_teleporter_green_8.xpos",              "7"                     },
-  { "mm_teleporter_green_8.ypos",              "6"                     },
-  { "mm_teleporter_green_8.frames",            "1"                     },
-  { "mm_teleporter_green_9",                   "RocksDF.png"           },
-  { "mm_teleporter_green_9.xpos",              "8"                     },
-  { "mm_teleporter_green_9.ypos",              "6"                     },
-  { "mm_teleporter_green_9.frames",            "1"                     },
-  { "mm_teleporter_green_10",                  "RocksDF.png"           },
-  { "mm_teleporter_green_10.xpos",             "9"                     },
-  { "mm_teleporter_green_10.ypos",             "6"                     },
-  { "mm_teleporter_green_10.frames",           "1"                     },
-  { "mm_teleporter_green_11",                  "RocksDF.png"           },
-  { "mm_teleporter_green_11.xpos",             "10"                    },
-  { "mm_teleporter_green_11.ypos",             "6"                     },
-  { "mm_teleporter_green_11.frames",           "1"                     },
-  { "mm_teleporter_green_12",                  "RocksDF.png"           },
-  { "mm_teleporter_green_12.xpos",             "11"                    },
-  { "mm_teleporter_green_12.ypos",             "6"                     },
-  { "mm_teleporter_green_12.frames",           "1"                     },
-  { "mm_teleporter_green_13",                  "RocksDF.png"           },
-  { "mm_teleporter_green_13.xpos",             "12"                    },
-  { "mm_teleporter_green_13.ypos",             "6"                     },
-  { "mm_teleporter_green_13.frames",           "1"                     },
-  { "mm_teleporter_green_14",                  "RocksDF.png"           },
-  { "mm_teleporter_green_14.xpos",             "13"                    },
-  { "mm_teleporter_green_14.ypos",             "6"                     },
-  { "mm_teleporter_green_14.frames",           "1"                     },
-  { "mm_teleporter_green_15",                  "RocksDF.png"           },
-  { "mm_teleporter_green_15.xpos",             "14"                    },
-  { "mm_teleporter_green_15.ypos",             "6"                     },
-  { "mm_teleporter_green_15.frames",           "1"                     },
-  { "mm_teleporter_green_16",                  "RocksDF.png"           },
-  { "mm_teleporter_green_16.xpos",             "15"                    },
-  { "mm_teleporter_green_16.ypos",             "6"                     },
-  { "mm_teleporter_green_16.frames",           "1"                     },
-
-  { "mm_teleporter_blue_1",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_1.xpos",               "0"                     },
-  { "mm_teleporter_blue_1.ypos",               "7"                     },
-  { "mm_teleporter_blue_1.frames",             "1"                     },
-  { "mm_teleporter_blue_2",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_2.xpos",               "1"                     },
-  { "mm_teleporter_blue_2.ypos",               "7"                     },
-  { "mm_teleporter_blue_2.frames",             "1"                     },
-  { "mm_teleporter_blue_3",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_3.xpos",               "2"                     },
-  { "mm_teleporter_blue_3.ypos",               "7"                     },
-  { "mm_teleporter_blue_3.frames",             "1"                     },
-  { "mm_teleporter_blue_4",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_4.xpos",               "3"                     },
-  { "mm_teleporter_blue_4.ypos",               "7"                     },
-  { "mm_teleporter_blue_4.frames",             "1"                     },
-  { "mm_teleporter_blue_5",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_5.xpos",               "4"                     },
-  { "mm_teleporter_blue_5.ypos",               "7"                     },
-  { "mm_teleporter_blue_5.frames",             "1"                     },
-  { "mm_teleporter_blue_6",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_6.xpos",               "5"                     },
-  { "mm_teleporter_blue_6.ypos",               "7"                     },
-  { "mm_teleporter_blue_6.frames",             "1"                     },
-  { "mm_teleporter_blue_7",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_7.xpos",               "6"                     },
-  { "mm_teleporter_blue_7.ypos",               "7"                     },
-  { "mm_teleporter_blue_7.frames",             "1"                     },
-  { "mm_teleporter_blue_8",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_8.xpos",               "7"                     },
-  { "mm_teleporter_blue_8.ypos",               "7"                     },
-  { "mm_teleporter_blue_8.frames",             "1"                     },
-  { "mm_teleporter_blue_9",                    "RocksDF.png"           },
-  { "mm_teleporter_blue_9.xpos",               "8"                     },
-  { "mm_teleporter_blue_9.ypos",               "7"                     },
-  { "mm_teleporter_blue_9.frames",             "1"                     },
-  { "mm_teleporter_blue_10",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_10.xpos",              "9"                     },
-  { "mm_teleporter_blue_10.ypos",              "7"                     },
-  { "mm_teleporter_blue_10.frames",            "1"                     },
-  { "mm_teleporter_blue_11",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_11.xpos",              "10"                    },
-  { "mm_teleporter_blue_11.ypos",              "7"                     },
-  { "mm_teleporter_blue_11.frames",            "1"                     },
-  { "mm_teleporter_blue_12",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_12.xpos",              "11"                    },
-  { "mm_teleporter_blue_12.ypos",              "7"                     },
-  { "mm_teleporter_blue_12.frames",            "1"                     },
-  { "mm_teleporter_blue_13",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_13.xpos",              "12"                    },
-  { "mm_teleporter_blue_13.ypos",              "7"                     },
-  { "mm_teleporter_blue_13.frames",            "1"                     },
-  { "mm_teleporter_blue_14",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_14.xpos",              "13"                    },
-  { "mm_teleporter_blue_14.ypos",              "7"                     },
-  { "mm_teleporter_blue_14.frames",            "1"                     },
-  { "mm_teleporter_blue_15",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_15.xpos",              "14"                    },
-  { "mm_teleporter_blue_15.ypos",              "7"                     },
-  { "mm_teleporter_blue_15.frames",            "1"                     },
-  { "mm_teleporter_blue_16",                   "RocksDF.png"           },
-  { "mm_teleporter_blue_16.xpos",              "15"                    },
-  { "mm_teleporter_blue_16.ypos",              "7"                     },
-  { "mm_teleporter_blue_16.frames",            "1"                     },
-
-  { "mm_kettle",                               "RocksMM.png"           },
-  { "mm_kettle.xpos",                          "12"                    },
-  { "mm_kettle.ypos",                          "1"                     },
-  { "mm_kettle.frames",                                "1"                     },
-  { "mm_kettle.exploding",                     "RocksMM.png"           },
-  { "mm_kettle.exploding.xpos",                        "13"                    },
-  { "mm_kettle.exploding.ypos",                        "1"                     },
-  { "mm_kettle.exploding.frames",              "3"                     },
-  { "mm_kettle.exploding.delay",               "4"                     },
-  { "mm_kettle.exploding.anim_mode",           "linear"                },
-
-  { "mm_bomb",                                 "RocksMM.png"           },
-  { "mm_bomb.xpos",                            "5"                     },
-  { "mm_bomb.ypos",                            "2"                     },
-  { "mm_bomb.frames",                          "1"                     },
-
-  { "mm_prism",                                        "RocksMM.png"           },
-  { "mm_prism.xpos",                           "0"                     },
-  { "mm_prism.ypos",                           "2"                     },
-  { "mm_prism.frames",                         "1"                     },
-
-  { "mm_fuse",                                 "RocksMM.png"           },
-  { "mm_fuse.xpos",                            "7"                     },
-  { "mm_fuse.ypos",                            "2"                     },
-  { "mm_fuse.frames",                          "1"                     },
-  { "mm_fuse.active",                          "RocksMM.png"           },
-  { "mm_fuse.active.xpos",                     "6"                     },
-  { "mm_fuse.active.ypos",                     "2"                     },
-  { "mm_fuse.active.frames",                   "1"                     },
-
-  { "mm_steel_lock",                           "RocksMM.png"           },
-  { "mm_steel_lock.xpos",                      "8"                     },
-  { "mm_steel_lock.ypos",                      "2"                     },
-  { "mm_steel_lock.frames",                    "1"                     },
-
-  { "mm_wooden_lock",                          "RocksMM.png"           },
-  { "mm_wooden_lock.xpos",                     "9"                     },
-  { "mm_wooden_lock.ypos",                     "6"                     },
-  { "mm_wooden_lock.frames",                   "1"                     },
-
-  { "mm_steel_block",                          "RocksMM.png"           },
-  { "mm_steel_block.xpos",                     "8"                     },
-  { "mm_steel_block.ypos",                     "6"                     },
-  { "mm_steel_block.frames",                   "1"                     },
-
-  { "mm_wooden_block",                         "RocksMM.png"           },
-  { "mm_wooden_block.xpos",                    "4"                     },
-  { "mm_wooden_block.ypos",                    "2"                     },
-  { "mm_wooden_block.frames",                  "1"                     },
-
-  { "mm_key",                                  "RocksMM.png"           },
-  { "mm_key.xpos",                             "9"                     },
-  { "mm_key.ypos",                             "2"                     },
-  { "mm_key.frames",                           "1"                     },
-
-  { "mm_lightbulb",                            "RocksMM.png"           },
-  { "mm_lightbulb.xpos",                       "10"                    },
-  { "mm_lightbulb.ypos",                       "2"                     },
-  { "mm_lightbulb.frames",                     "1"                     },
-  { "mm_lightbulb.active",                     "RocksMM.png"           },
-  { "mm_lightbulb.active.xpos",                        "11"                    },
-  { "mm_lightbulb.active.ypos",                        "2"                     },
-  { "mm_lightbulb.active.frames",              "1"                     },
-
-  { "mm_lightball",                            "RocksMM.png"           },
-  { "mm_lightball.xpos",                       "12"                    },
-  { "mm_lightball.ypos",                       "2"                     },
-  { "mm_lightball.frames",                     "3"                     },
-  { "mm_lightball.delay",                      "1000000"               },
-  { "mm_lightball.anim_mode",                  "random"                },
-  { "mm_lightball_red",                                "RocksMM.png"           },
-  { "mm_lightball_red.xpos",                   "12"                    },
-  { "mm_lightball_red.ypos",                   "2"                     },
-  { "mm_lightball_red.frames",                 "1"                     },
-  { "mm_lightball_blue",                       "RocksMM.png"           },
-  { "mm_lightball_blue.xpos",                  "13"                    },
-  { "mm_lightball_blue.ypos",                  "2"                     },
-  { "mm_lightball_blue.frames",                        "1"                     },
-  { "mm_lightball_yellow",                     "RocksMM.png"           },
-  { "mm_lightball_yellow.xpos",                        "14"                    },
-  { "mm_lightball_yellow.ypos",                        "2"                     },
-  { "mm_lightball_yellow.frames",              "1"                     },
-
-  { "mm_gray_ball",                            "RocksMM.png"           },
-  { "mm_gray_ball.xpos",                       "15"                    },
-  { "mm_gray_ball.ypos",                       "2"                     },
-  { "mm_gray_ball.frames",                     "1"                     },
-
-  { "mm_fuel_full",                            "RocksMM.png"           },
-  { "mm_fuel_full.xpos",                       "10"                    },
-  { "mm_fuel_full.ypos",                       "6"                     },
-  { "mm_fuel_full.frames",                     "1"                     },
-  { "mm_fuel_empty",                           "RocksMM.png"           },
-  { "mm_fuel_empty.xpos",                      "11"                    },
-  { "mm_fuel_empty.ypos",                      "6"                     },
-  { "mm_fuel_empty.frames",                    "1"                     },
-
-  { "mm_steel_wall",                           "RocksMM.png"           },
-  { "mm_steel_wall.xpos",                      "0"                     },
-  { "mm_steel_wall.ypos",                      "7"                     },
-  { "mm_steel_wall.frames",                    "1"                     },
-
-  { "mm_wooden_wall",                          "RocksMM.png"           },
-  { "mm_wooden_wall.xpos",                     "1"                     },
-  { "mm_wooden_wall.ypos",                     "7"                     },
-  { "mm_wooden_wall.frames",                   "1"                     },
-
-  { "mm_ice_wall",                             "RocksMM.png"           },
-  { "mm_ice_wall.xpos",                                "2"                     },
-  { "mm_ice_wall.ypos",                                "7"                     },
-  { "mm_ice_wall.frames",                      "1"                     },
-  { "mm_ice_wall.shrinking",                   "RocksMM.png"           },
-  { "mm_ice_wall.shrinking.xpos",              "2"                     },
-  { "mm_ice_wall.shrinking.ypos",              "7"                     },
-  { "mm_ice_wall.shrinking.frames",            "5"                     },
-  { "mm_ice_wall.shrinking.delay",             "8"                     },
-  { "mm_ice_wall.shrinking.anim_mode",         "linear"                },
-
-  { "mm_amoeba_wall",                          "RocksMM.png"           },
-  { "mm_amoeba_wall.xpos",                     "8"                     },
-  { "mm_amoeba_wall.ypos",                     "7"                     },
-  { "mm_amoeba_wall.frames",                   "1"                     },
-  { "mm_amoeba_wall.growing",                  "RocksMM.png"           },
-  { "mm_amoeba_wall.growing.xpos",             "8"                     },
-  { "mm_amoeba_wall.growing.ypos",             "7"                     },
-  { "mm_amoeba_wall.growing.frames",           "5"                     },
-  { "mm_amoeba_wall.growing.delay",            "8"                     },
-  { "mm_amoeba_wall.growing.anim_mode",                "linear,reverse"        },
-
-  { "mm_pacman",                               "RocksMM.png"           },
-  { "mm_pacman.xpos",                          "0"                     },
-  { "mm_pacman.ypos",                          "4"                     },
-  { "mm_pacman.frames",                                "1"                     },
-  { "mm_pacman.right",                         "RocksMM.png"           },
-  { "mm_pacman.right.xpos",                    "0"                     },
-  { "mm_pacman.right.ypos",                    "4"                     },
-  { "mm_pacman.right.frames",                  "1"                     },
-  { "mm_pacman.up",                            "RocksMM.png"           },
-  { "mm_pacman.up.xpos",                       "1"                     },
-  { "mm_pacman.up.ypos",                       "4"                     },
-  { "mm_pacman.up.frames",                     "1"                     },
-  { "mm_pacman.left",                          "RocksMM.png"           },
-  { "mm_pacman.left.xpos",                     "2"                     },
-  { "mm_pacman.left.ypos",                     "4"                     },
-  { "mm_pacman.left.frames",                   "1"                     },
-  { "mm_pacman.down",                          "RocksMM.png"           },
-  { "mm_pacman.down.xpos",                     "3"                     },
-  { "mm_pacman.down.ypos",                     "4"                     },
-  { "mm_pacman.down.frames",                   "1"                     },
-  { "mm_pacman.eating.right",                  "RocksMM.png"           },
-  { "mm_pacman.eating.right.xpos",             "4"                     },
-  { "mm_pacman.eating.right.ypos",             "4"                     },
-  { "mm_pacman.eating.right.frames",           "1"                     },
-  { "mm_pacman.eating.up",                     "RocksMM.png"           },
-  { "mm_pacman.eating.up.xpos",                        "5"                     },
-  { "mm_pacman.eating.up.ypos",                        "4"                     },
-  { "mm_pacman.eating.up.frames",              "1"                     },
-  { "mm_pacman.eating.left",                   "RocksMM.png"           },
-  { "mm_pacman.eating.left.xpos",              "6"                     },
-  { "mm_pacman.eating.left.ypos",              "4"                     },
-  { "mm_pacman.eating.left.frames",            "1"                     },
-  { "mm_pacman.eating.down",                   "RocksMM.png"           },
-  { "mm_pacman.eating.down.xpos",              "7"                     },
-  { "mm_pacman.eating.down.ypos",              "4"                     },
-  { "mm_pacman.eating.down.frames",            "1"                     },
-
-  { "mm_mask_mcduffin.right",                  "RocksMM.png"           },
-  { "mm_mask_mcduffin.right.xpos",             "8"                     },
-  { "mm_mask_mcduffin.right.ypos",             "8"                     },
-  { "mm_mask_mcduffin.right.frames",           "1"                     },
-  { "mm_mask_mcduffin.up",                     "RocksMM.png"           },
-  { "mm_mask_mcduffin.up.xpos",                        "9"                     },
-  { "mm_mask_mcduffin.up.ypos",                        "8"                     },
-  { "mm_mask_mcduffin.up.frames",              "1"                     },
-  { "mm_mask_mcduffin.left",                   "RocksMM.png"           },
-  { "mm_mask_mcduffin.left.xpos",              "10"                    },
-  { "mm_mask_mcduffin.left.ypos",              "8"                     },
-  { "mm_mask_mcduffin.left.frames",            "1"                     },
-  { "mm_mask_mcduffin.down",                   "RocksMM.png"           },
-  { "mm_mask_mcduffin.down.xpos",              "11"                    },
-  { "mm_mask_mcduffin.down.ypos",              "8"                     },
-  { "mm_mask_mcduffin.down.frames",            "1"                     },
-
-  { "mm_mask_grid_1",                          "RocksMM.png"           },
-  { "mm_mask_grid_1.xpos",                     "4"                     },
-  { "mm_mask_grid_1.ypos",                     "8"                     },
-  { "mm_mask_grid_1.frames",                   "1"                     },
-  { "mm_mask_grid_2",                          "RocksMM.png"           },
-  { "mm_mask_grid_2.xpos",                     "5"                     },
-  { "mm_mask_grid_2.ypos",                     "8"                     },
-  { "mm_mask_grid_2.frames",                   "1"                     },
-  { "mm_mask_grid_3",                          "RocksMM.png"           },
-  { "mm_mask_grid_3.xpos",                     "6"                     },
-  { "mm_mask_grid_3.ypos",                     "8"                     },
-  { "mm_mask_grid_3.frames",                   "1"                     },
-  { "mm_mask_grid_4",                          "RocksMM.png"           },
-  { "mm_mask_grid_4.xpos",                     "7"                     },
-  { "mm_mask_grid_4.ypos",                     "8"                     },
-  { "mm_mask_grid_4.frames",                   "1"                     },
-
-  { "mm_mask_rectangle",                       "RocksMM.png"           },
-  { "mm_mask_rectangle.xpos",                  "1"                     },
-  { "mm_mask_rectangle.ypos",                  "8"                     },
-  { "mm_mask_rectangle.frames",                        "1"                     },
-
-  { "mm_mask_circle",                          "RocksMM.png"           },
-  { "mm_mask_circle.xpos",                     "0"                     },
-  { "mm_mask_circle.ypos",                     "8"                     },
-  { "mm_mask_circle.frames",                   "1"                     },
-
-  { "[mm_default].exploding",                  "RocksMM.png"           },
-  { "[mm_default].exploding.xpos",             "8"                     },
-  { "[mm_default].exploding.ypos",             "4"                     },
-  { "[mm_default].exploding.frames",           "8"                     },
-  { "[mm_default].exploding.delay",            "2"                     },
-  { "[mm_default].exploding.anim_mode",                "linear"                },
-
-  { "df_laser",                                        "RocksDF.png"           },
-  { "df_laser.xpos",                           "0"                     },
-  { "df_laser.ypos",                           "9"                     },
-  { "df_laser.frames",                         "4"                     },
-  { "df_laser.delay",                          "8"                     },
-  { "df_laser.right",                          "RocksDF.png"           },
-  { "df_laser.right.xpos",                     "0"                     },
-  { "df_laser.right.ypos",                     "9"                     },
-  { "df_laser.right.frames",                   "1"                     },
-  { "df_laser.up",                             "RocksDF.png"           },
-  { "df_laser.up.xpos",                                "1"                     },
-  { "df_laser.up.ypos",                                "9"                     },
-  { "df_laser.up.frames",                      "1"                     },
-  { "df_laser.left",                           "RocksDF.png"           },
-  { "df_laser.left.xpos",                      "2"                     },
-  { "df_laser.left.ypos",                      "9"                     },
-  { "df_laser.left.frames",                    "1"                     },
-  { "df_laser.down",                           "RocksDF.png"           },
-  { "df_laser.down.xpos",                      "3"                     },
-  { "df_laser.down.ypos",                      "9"                     },
-  { "df_laser.down.frames",                    "1"                     },
-
-  { "df_receiver",                             "RocksDF.png"           },
-  { "df_receiver.xpos",                                "4"                     },
-  { "df_receiver.ypos",                                "9"                     },
-  { "df_receiver.frames",                      "4"                     },
-  { "df_receiver.delay",                       "8"                     },
-  { "df_receiver.right",                       "RocksDF.png"           },
-  { "df_receiver.right.xpos",                  "4"                     },
-  { "df_receiver.right.ypos",                  "9"                     },
-  { "df_receiver.right.frames",                        "1"                     },
-  { "df_receiver.up",                          "RocksDF.png"           },
-  { "df_receiver.up.xpos",                     "5"                     },
-  { "df_receiver.up.ypos",                     "9"                     },
-  { "df_receiver.up.frames",                   "1"                     },
-  { "df_receiver.left",                                "RocksDF.png"           },
-  { "df_receiver.left.xpos",                   "6"                     },
-  { "df_receiver.left.ypos",                   "9"                     },
-  { "df_receiver.left.frames",                 "1"                     },
-  { "df_receiver.down",                                "RocksDF.png"           },
-  { "df_receiver.down.xpos",                   "7"                     },
-  { "df_receiver.down.ypos",                   "9"                     },
-  { "df_receiver.down.frames",                 "1"                     },
-
-  { "df_mirror_1",                             "RocksDF.png"           },
-  { "df_mirror_1.xpos",                                "0"                     },
-  { "df_mirror_1.ypos",                                "0"                     },
-  { "df_mirror_1.frames",                      "1"                     },
-  { "df_mirror_2",                             "RocksDF.png"           },
-  { "df_mirror_2.xpos",                                "1"                     },
-  { "df_mirror_2.ypos",                                "0"                     },
-  { "df_mirror_2.frames",                      "1"                     },
-  { "df_mirror_3",                             "RocksDF.png"           },
-  { "df_mirror_3.xpos",                                "2"                     },
-  { "df_mirror_3.ypos",                                "0"                     },
-  { "df_mirror_3.frames",                      "1"                     },
-  { "df_mirror_4",                             "RocksDF.png"           },
-  { "df_mirror_4.xpos",                                "3"                     },
-  { "df_mirror_4.ypos",                                "0"                     },
-  { "df_mirror_4.frames",                      "1"                     },
-  { "df_mirror_5",                             "RocksDF.png"           },
-  { "df_mirror_5.xpos",                                "4"                     },
-  { "df_mirror_5.ypos",                                "0"                     },
-  { "df_mirror_5.frames",                      "1"                     },
-  { "df_mirror_6",                             "RocksDF.png"           },
-  { "df_mirror_6.xpos",                                "5"                     },
-  { "df_mirror_6.ypos",                                "0"                     },
-  { "df_mirror_6.frames",                      "1"                     },
-  { "df_mirror_7",                             "RocksDF.png"           },
-  { "df_mirror_7.xpos",                                "6"                     },
-  { "df_mirror_7.ypos",                                "0"                     },
-  { "df_mirror_7.frames",                      "1"                     },
-  { "df_mirror_8",                             "RocksDF.png"           },
-  { "df_mirror_8.xpos",                                "7"                     },
-  { "df_mirror_8.ypos",                                "0"                     },
-  { "df_mirror_8.frames",                      "1"                     },
-  { "df_mirror_9",                             "RocksDF.png"           },
-  { "df_mirror_9.xpos",                                "8"                     },
-  { "df_mirror_9.ypos",                                "0"                     },
-  { "df_mirror_9.frames",                      "1"                     },
-  { "df_mirror_10",                            "RocksDF.png"           },
-  { "df_mirror_10.xpos",                       "9"                     },
-  { "df_mirror_10.ypos",                       "0"                     },
-  { "df_mirror_10.frames",                     "1"                     },
-  { "df_mirror_11",                            "RocksDF.png"           },
-  { "df_mirror_11.xpos",                       "10"                    },
-  { "df_mirror_11.ypos",                       "0"                     },
-  { "df_mirror_11.frames",                     "1"                     },
-  { "df_mirror_12",                            "RocksDF.png"           },
-  { "df_mirror_12.xpos",                       "11"                    },
-  { "df_mirror_12.ypos",                       "0"                     },
-  { "df_mirror_12.frames",                     "1"                     },
-  { "df_mirror_13",                            "RocksDF.png"           },
-  { "df_mirror_13.xpos",                       "12"                    },
-  { "df_mirror_13.ypos",                       "0"                     },
-  { "df_mirror_13.frames",                     "1"                     },
-  { "df_mirror_14",                            "RocksDF.png"           },
-  { "df_mirror_14.xpos",                       "13"                    },
-  { "df_mirror_14.ypos",                       "0"                     },
-  { "df_mirror_14.frames",                     "1"                     },
-  { "df_mirror_15",                            "RocksDF.png"           },
-  { "df_mirror_15.xpos",                       "14"                    },
-  { "df_mirror_15.ypos",                       "0"                     },
-  { "df_mirror_15.frames",                     "1"                     },
-  { "df_mirror_16",                            "RocksDF.png"           },
-  { "df_mirror_16.xpos",                       "15"                    },
-  { "df_mirror_16.ypos",                       "0"                     },
-  { "df_mirror_16.frames",                     "1"                     },
-
-  { "df_mirror_rotating_1",                    "RocksDF.png"           },
-  { "df_mirror_rotating_1.xpos",               "0"                     },
-  { "df_mirror_rotating_1.ypos",               "0"                     },
-  { "df_mirror_rotating_1.frames",             "1"                     },
-  { "df_mirror_rotating_1.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_1.EDITOR.xpos",                "0"                     },
-  { "df_mirror_rotating_1.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_1.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_2",                    "RocksDF.png"           },
-  { "df_mirror_rotating_2.xpos",               "1"                     },
-  { "df_mirror_rotating_2.ypos",               "0"                     },
-  { "df_mirror_rotating_2.frames",             "1"                     },
-  { "df_mirror_rotating_2.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_2.EDITOR.xpos",                "1"                     },
-  { "df_mirror_rotating_2.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_2.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_3",                    "RocksDF.png"           },
-  { "df_mirror_rotating_3.xpos",               "2"                     },
-  { "df_mirror_rotating_3.ypos",               "0"                     },
-  { "df_mirror_rotating_3.frames",             "1"                     },
-  { "df_mirror_rotating_3.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_3.EDITOR.xpos",                "2"                     },
-  { "df_mirror_rotating_3.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_3.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_4",                    "RocksDF.png"           },
-  { "df_mirror_rotating_4.xpos",               "3"                     },
-  { "df_mirror_rotating_4.ypos",               "0"                     },
-  { "df_mirror_rotating_4.frames",             "1"                     },
-  { "df_mirror_rotating_4.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_4.EDITOR.xpos",                "3"                     },
-  { "df_mirror_rotating_4.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_4.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_5",                    "RocksDF.png"           },
-  { "df_mirror_rotating_5.xpos",               "4"                     },
-  { "df_mirror_rotating_5.ypos",               "0"                     },
-  { "df_mirror_rotating_5.frames",             "1"                     },
-  { "df_mirror_rotating_5.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_5.EDITOR.xpos",                "4"                     },
-  { "df_mirror_rotating_5.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_5.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_6",                    "RocksDF.png"           },
-  { "df_mirror_rotating_6.xpos",               "5"                     },
-  { "df_mirror_rotating_6.ypos",               "0"                     },
-  { "df_mirror_rotating_6.frames",             "1"                     },
-  { "df_mirror_rotating_6.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_6.EDITOR.xpos",                "5"                     },
-  { "df_mirror_rotating_6.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_6.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_7",                    "RocksDF.png"           },
-  { "df_mirror_rotating_7.xpos",               "6"                     },
-  { "df_mirror_rotating_7.ypos",               "0"                     },
-  { "df_mirror_rotating_7.frames",             "1"                     },
-  { "df_mirror_rotating_7.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_7.EDITOR.xpos",                "6"                     },
-  { "df_mirror_rotating_7.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_7.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_8",                    "RocksDF.png"           },
-  { "df_mirror_rotating_8.xpos",               "7"                     },
-  { "df_mirror_rotating_8.ypos",               "0"                     },
-  { "df_mirror_rotating_8.frames",             "1"                     },
-  { "df_mirror_rotating_8.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_8.EDITOR.xpos",                "7"                     },
-  { "df_mirror_rotating_8.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_8.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_9",                    "RocksDF.png"           },
-  { "df_mirror_rotating_9.xpos",               "8"                     },
-  { "df_mirror_rotating_9.ypos",               "0"                     },
-  { "df_mirror_rotating_9.frames",             "1"                     },
-  { "df_mirror_rotating_9.EDITOR",             "RocksDF.png"           },
-  { "df_mirror_rotating_9.EDITOR.xpos",                "8"                     },
-  { "df_mirror_rotating_9.EDITOR.ypos",                "1"                     },
-  { "df_mirror_rotating_9.EDITOR.frames",      "1"                     },
-  { "df_mirror_rotating_10",                   "RocksDF.png"           },
-  { "df_mirror_rotating_10.xpos",              "9"                     },
-  { "df_mirror_rotating_10.ypos",              "0"                     },
-  { "df_mirror_rotating_10.frames",            "1"                     },
-  { "df_mirror_rotating_10.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_10.EDITOR.xpos",       "9"                     },
-  { "df_mirror_rotating_10.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_10.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_11",                   "RocksDF.png"           },
-  { "df_mirror_rotating_11.xpos",              "10"                    },
-  { "df_mirror_rotating_11.ypos",              "0"                     },
-  { "df_mirror_rotating_11.frames",            "1"                     },
-  { "df_mirror_rotating_11.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_11.EDITOR.xpos",       "10"                    },
-  { "df_mirror_rotating_11.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_11.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_12",                   "RocksDF.png"           },
-  { "df_mirror_rotating_12.xpos",              "11"                    },
-  { "df_mirror_rotating_12.ypos",              "0"                     },
-  { "df_mirror_rotating_12.frames",            "1"                     },
-  { "df_mirror_rotating_12.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_12.EDITOR.xpos",       "11"                    },
-  { "df_mirror_rotating_12.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_12.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_13",                   "RocksDF.png"           },
-  { "df_mirror_rotating_13.xpos",              "12"                    },
-  { "df_mirror_rotating_13.ypos",              "0"                     },
-  { "df_mirror_rotating_13.frames",            "1"                     },
-  { "df_mirror_rotating_13.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_13.EDITOR.xpos",       "12"                    },
-  { "df_mirror_rotating_13.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_13.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_14",                   "RocksDF.png"           },
-  { "df_mirror_rotating_14.xpos",              "13"                    },
-  { "df_mirror_rotating_14.ypos",              "0"                     },
-  { "df_mirror_rotating_14.frames",            "1"                     },
-  { "df_mirror_rotating_14.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_14.EDITOR.xpos",       "13"                    },
-  { "df_mirror_rotating_14.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_14.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_15",                   "RocksDF.png"           },
-  { "df_mirror_rotating_15.xpos",              "14"                    },
-  { "df_mirror_rotating_15.ypos",              "0"                     },
-  { "df_mirror_rotating_15.frames",            "1"                     },
-  { "df_mirror_rotating_15.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_15.EDITOR.xpos",       "14"                    },
-  { "df_mirror_rotating_15.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_15.EDITOR.frames",     "1"                     },
-  { "df_mirror_rotating_16",                   "RocksDF.png"           },
-  { "df_mirror_rotating_16.xpos",              "15"                    },
-  { "df_mirror_rotating_16.ypos",              "0"                     },
-  { "df_mirror_rotating_16.frames",            "1"                     },
-  { "df_mirror_rotating_16.EDITOR",            "RocksDF.png"           },
-  { "df_mirror_rotating_16.EDITOR.xpos",       "15"                    },
-  { "df_mirror_rotating_16.EDITOR.ypos",       "1"                     },
-  { "df_mirror_rotating_16.EDITOR.frames",     "1"                     },
-
-  { "df_steel_grid_fixed_1",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_1.xpos",              "0"                     },
-  { "df_steel_grid_fixed_1.ypos",              "2"                     },
-  { "df_steel_grid_fixed_1.frames",            "1"                     },
-  { "df_steel_grid_fixed_2",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_2.xpos",              "1"                     },
-  { "df_steel_grid_fixed_2.ypos",              "2"                     },
-  { "df_steel_grid_fixed_2.frames",            "1"                     },
-  { "df_steel_grid_fixed_3",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_3.xpos",              "2"                     },
-  { "df_steel_grid_fixed_3.ypos",              "2"                     },
-  { "df_steel_grid_fixed_3.frames",            "1"                     },
-  { "df_steel_grid_fixed_4",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_4.xpos",              "3"                     },
-  { "df_steel_grid_fixed_4.ypos",              "2"                     },
-  { "df_steel_grid_fixed_4.frames",            "1"                     },
-  { "df_steel_grid_fixed_5",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_5.xpos",              "4"                     },
-  { "df_steel_grid_fixed_5.ypos",              "2"                     },
-  { "df_steel_grid_fixed_5.frames",            "1"                     },
-  { "df_steel_grid_fixed_6",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_6.xpos",              "5"                     },
-  { "df_steel_grid_fixed_6.ypos",              "2"                     },
-  { "df_steel_grid_fixed_6.frames",            "1"                     },
-  { "df_steel_grid_fixed_7",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_7.xpos",              "6"                     },
-  { "df_steel_grid_fixed_7.ypos",              "2"                     },
-  { "df_steel_grid_fixed_7.frames",            "1"                     },
-  { "df_steel_grid_fixed_8",                   "RocksDF.png"           },
-  { "df_steel_grid_fixed_8.xpos",              "7"                     },
-  { "df_steel_grid_fixed_8.ypos",              "2"                     },
-  { "df_steel_grid_fixed_8.frames",            "1"                     },
-
-  { "df_wooden_grid_fixed_1",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_1.xpos",             "8"                     },
-  { "df_wooden_grid_fixed_1.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_1.frames",           "1"                     },
-  { "df_wooden_grid_fixed_2",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_2.xpos",             "9"                     },
-  { "df_wooden_grid_fixed_2.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_2.frames",           "1"                     },
-  { "df_wooden_grid_fixed_3",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_3.xpos",             "10"                    },
-  { "df_wooden_grid_fixed_3.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_3.frames",           "1"                     },
-  { "df_wooden_grid_fixed_4",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_4.xpos",             "11"                    },
-  { "df_wooden_grid_fixed_4.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_4.frames",           "1"                     },
-  { "df_wooden_grid_fixed_5",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_5.xpos",             "12"                    },
-  { "df_wooden_grid_fixed_5.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_5.frames",           "1"                     },
-  { "df_wooden_grid_fixed_6",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_6.xpos",             "13"                    },
-  { "df_wooden_grid_fixed_6.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_6.frames",           "1"                     },
-  { "df_wooden_grid_fixed_7",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_7.xpos",             "14"                    },
-  { "df_wooden_grid_fixed_7.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_7.frames",           "1"                     },
-  { "df_wooden_grid_fixed_8",                  "RocksDF.png"           },
-  { "df_wooden_grid_fixed_8.xpos",             "15"                    },
-  { "df_wooden_grid_fixed_8.ypos",             "2"                     },
-  { "df_wooden_grid_fixed_8.frames",           "1"                     },
-
-  { "df_steel_grid_rotating_1",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_1.xpos",           "0"                     },
-  { "df_steel_grid_rotating_1.ypos",           "2"                     },
-  { "df_steel_grid_rotating_1.frames",         "1"                     },
-  { "df_steel_grid_rotating_1.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_1.EDITOR.xpos",    "0"                     },
-  { "df_steel_grid_rotating_1.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_1.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_2",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_2.xpos",           "1"                     },
-  { "df_steel_grid_rotating_2.ypos",           "2"                     },
-  { "df_steel_grid_rotating_2.frames",         "1"                     },
-  { "df_steel_grid_rotating_2.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_2.EDITOR.xpos",    "1"                     },
-  { "df_steel_grid_rotating_2.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_2.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_3",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_3.xpos",           "2"                     },
-  { "df_steel_grid_rotating_3.ypos",           "2"                     },
-  { "df_steel_grid_rotating_3.frames",         "1"                     },
-  { "df_steel_grid_rotating_3.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_3.EDITOR.xpos",    "2"                     },
-  { "df_steel_grid_rotating_3.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_3.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_4",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_4.xpos",           "3"                     },
-  { "df_steel_grid_rotating_4.ypos",           "2"                     },
-  { "df_steel_grid_rotating_4.frames",         "1"                     },
-  { "df_steel_grid_rotating_4.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_4.EDITOR.xpos",    "3"                     },
-  { "df_steel_grid_rotating_4.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_4.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_5",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_5.xpos",           "4"                     },
-  { "df_steel_grid_rotating_5.ypos",           "2"                     },
-  { "df_steel_grid_rotating_5.frames",         "1"                     },
-  { "df_steel_grid_rotating_5.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_5.EDITOR.xpos",    "4"                     },
-  { "df_steel_grid_rotating_5.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_5.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_6",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_6.xpos",           "5"                     },
-  { "df_steel_grid_rotating_6.ypos",           "2"                     },
-  { "df_steel_grid_rotating_6.frames",         "1"                     },
-  { "df_steel_grid_rotating_6.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_6.EDITOR.xpos",    "5"                     },
-  { "df_steel_grid_rotating_6.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_6.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_7",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_7.xpos",           "6"                     },
-  { "df_steel_grid_rotating_7.ypos",           "2"                     },
-  { "df_steel_grid_rotating_7.frames",         "1"                     },
-  { "df_steel_grid_rotating_7.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_7.EDITOR.xpos",    "6"                     },
-  { "df_steel_grid_rotating_7.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_7.EDITOR.frames",  "1"                     },
-  { "df_steel_grid_rotating_8",                        "RocksDF.png"           },
-  { "df_steel_grid_rotating_8.xpos",           "7"                     },
-  { "df_steel_grid_rotating_8.ypos",           "2"                     },
-  { "df_steel_grid_rotating_8.frames",         "1"                     },
-  { "df_steel_grid_rotating_8.EDITOR",         "RocksDF.png"           },
-  { "df_steel_grid_rotating_8.EDITOR.xpos",    "7"                     },
-  { "df_steel_grid_rotating_8.EDITOR.ypos",    "3"                     },
-  { "df_steel_grid_rotating_8.EDITOR.frames",  "1"                     },
-
-  { "df_wooden_grid_rotating_1",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_1.xpos",          "8"                     },
-  { "df_wooden_grid_rotating_1.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_1.frames",                "1"                     },
-  { "df_wooden_grid_rotating_1.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_1.EDITOR.xpos",   "8"                     },
-  { "df_wooden_grid_rotating_1.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_1.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_2",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_2.xpos",          "9"                     },
-  { "df_wooden_grid_rotating_2.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_2.frames",                "1"                     },
-  { "df_wooden_grid_rotating_2.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_2.EDITOR.xpos",   "9"                     },
-  { "df_wooden_grid_rotating_2.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_2.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_3",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_3.xpos",          "10"                    },
-  { "df_wooden_grid_rotating_3.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_3.frames",                "1"                     },
-  { "df_wooden_grid_rotating_3.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_3.EDITOR.xpos",   "10"                    },
-  { "df_wooden_grid_rotating_3.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_3.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_4",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_4.xpos",          "11"                    },
-  { "df_wooden_grid_rotating_4.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_4.frames",                "1"                     },
-  { "df_wooden_grid_rotating_4.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_4.EDITOR.xpos",   "11"                    },
-  { "df_wooden_grid_rotating_4.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_4.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_5",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_5.xpos",          "12"                    },
-  { "df_wooden_grid_rotating_5.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_5.frames",                "1"                     },
-  { "df_wooden_grid_rotating_5.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_5.EDITOR.xpos",   "12"                    },
-  { "df_wooden_grid_rotating_5.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_5.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_6",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_6.xpos",          "13"                    },
-  { "df_wooden_grid_rotating_6.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_6.frames",                "1"                     },
-  { "df_wooden_grid_rotating_6.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_6.EDITOR.xpos",   "13"                    },
-  { "df_wooden_grid_rotating_6.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_6.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_7",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_7.xpos",          "14"                    },
-  { "df_wooden_grid_rotating_7.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_7.frames",                "1"                     },
-  { "df_wooden_grid_rotating_7.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_7.EDITOR.xpos",   "14"                    },
-  { "df_wooden_grid_rotating_7.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_7.EDITOR.frames", "1"                     },
-  { "df_wooden_grid_rotating_8",               "RocksDF.png"           },
-  { "df_wooden_grid_rotating_8.xpos",          "15"                    },
-  { "df_wooden_grid_rotating_8.ypos",          "2"                     },
-  { "df_wooden_grid_rotating_8.frames",                "1"                     },
-  { "df_wooden_grid_rotating_8.EDITOR",                "RocksDF.png"           },
-  { "df_wooden_grid_rotating_8.EDITOR.xpos",   "15"                    },
-  { "df_wooden_grid_rotating_8.EDITOR.ypos",   "3"                     },
-  { "df_wooden_grid_rotating_8.EDITOR.frames", "1"                     },
-
-  { "df_fibre_optic_red_1",                    "RocksDF.png"           },
-  { "df_fibre_optic_red_1.xpos",               "8"                     },
-  { "df_fibre_optic_red_1.ypos",               "8"                     },
-  { "df_fibre_optic_red_1.frames",             "1"                     },
-  { "df_fibre_optic_red_1.EDITOR",             "RocksDF.png"           },
-  { "df_fibre_optic_red_1.EDITOR.xpos",                "8"                     },
-  { "df_fibre_optic_red_1.EDITOR.ypos",                "9"                     },
-  { "df_fibre_optic_red_1.EDITOR.frames",      "1"                     },
-  { "df_fibre_optic_red_2",                    "RocksDF.png"           },
-  { "df_fibre_optic_red_2.xpos",               "9"                     },
-  { "df_fibre_optic_red_2.ypos",               "8"                     },
-  { "df_fibre_optic_red_2.frames",             "1"                     },
-  { "df_fibre_optic_red_2.EDITOR",             "RocksDF.png"           },
-  { "df_fibre_optic_red_2.EDITOR.xpos",                "9"                     },
-  { "df_fibre_optic_red_2.EDITOR.ypos",                "9"                     },
-  { "df_fibre_optic_red_2.EDITOR.frames",      "1"                     },
-  { "df_fibre_optic_yellow_1",                 "RocksDF.png"           },
-  { "df_fibre_optic_yellow_1.xpos",            "10"                    },
-  { "df_fibre_optic_yellow_1.ypos",            "8"                     },
-  { "df_fibre_optic_yellow_1.frames",          "1"                     },
-  { "df_fibre_optic_yellow_1.EDITOR",          "RocksDF.png"           },
-  { "df_fibre_optic_yellow_1.EDITOR.xpos",     "10"                    },
-  { "df_fibre_optic_yellow_1.EDITOR.ypos",     "9"                     },
-  { "df_fibre_optic_yellow_1.EDITOR.frames",   "1"                     },
-  { "df_fibre_optic_yellow_2",                 "RocksDF.png"           },
-  { "df_fibre_optic_yellow_2.xpos",            "11"                    },
-  { "df_fibre_optic_yellow_2.ypos",            "8"                     },
-  { "df_fibre_optic_yellow_2.frames",          "1"                     },
-  { "df_fibre_optic_yellow_2.EDITOR",          "RocksDF.png"           },
-  { "df_fibre_optic_yellow_2.EDITOR.xpos",     "11"                    },
-  { "df_fibre_optic_yellow_2.EDITOR.ypos",     "9"                     },
-  { "df_fibre_optic_yellow_2.EDITOR.frames",   "1"                     },
-  { "df_fibre_optic_green_1",                  "RocksDF.png"           },
-  { "df_fibre_optic_green_1.xpos",             "12"                    },
-  { "df_fibre_optic_green_1.ypos",             "8"                     },
-  { "df_fibre_optic_green_1.frames",           "1"                     },
-  { "df_fibre_optic_green_1.EDITOR",           "RocksDF.png"           },
-  { "df_fibre_optic_green_1.EDITOR.xpos",      "12"                    },
-  { "df_fibre_optic_green_1.EDITOR.ypos",      "9"                     },
-  { "df_fibre_optic_green_1.EDITOR.frames",    "1"                     },
-  { "df_fibre_optic_green_2",                  "RocksDF.png"           },
-  { "df_fibre_optic_green_2.xpos",             "13"                    },
-  { "df_fibre_optic_green_2.ypos",             "8"                     },
-  { "df_fibre_optic_green_2.frames",           "1"                     },
-  { "df_fibre_optic_green_2.EDITOR",           "RocksDF.png"           },
-  { "df_fibre_optic_green_2.EDITOR.xpos",      "13"                    },
-  { "df_fibre_optic_green_2.EDITOR.ypos",      "9"                     },
-  { "df_fibre_optic_green_2.EDITOR.frames",    "1"                     },
-  { "df_fibre_optic_blue_1",                   "RocksDF.png"           },
-  { "df_fibre_optic_blue_1.xpos",              "14"                    },
-  { "df_fibre_optic_blue_1.ypos",              "8"                     },
-  { "df_fibre_optic_blue_1.frames",            "1"                     },
-  { "df_fibre_optic_blue_1.EDITOR",            "RocksDF.png"           },
-  { "df_fibre_optic_blue_1.EDITOR.xpos",       "14"                    },
-  { "df_fibre_optic_blue_1.EDITOR.ypos",       "9"                     },
-  { "df_fibre_optic_blue_1.EDITOR.frames",     "1"                     },
-  { "df_fibre_optic_blue_2",                   "RocksDF.png"           },
-  { "df_fibre_optic_blue_2.xpos",              "15"                    },
-  { "df_fibre_optic_blue_2.ypos",              "8"                     },
-  { "df_fibre_optic_blue_2.frames",            "1"                     },
-  { "df_fibre_optic_blue_2.EDITOR",            "RocksDF.png"           },
-  { "df_fibre_optic_blue_2.EDITOR.xpos",       "15"                    },
-  { "df_fibre_optic_blue_2.EDITOR.ypos",       "9"                     },
-  { "df_fibre_optic_blue_2.EDITOR.frames",     "1"                     },
-
-  { "df_steel_wall",                           "RocksDF.png"           },
-  { "df_steel_wall.xpos",                      "6"                     },
-  { "df_steel_wall.ypos",                      "8"                     },
-  { "df_steel_wall.frames",                    "1"                     },
-
-  { "df_wooden_wall",                          "RocksDF.png"           },
-  { "df_wooden_wall.xpos",                     "7"                     },
-  { "df_wooden_wall.ypos",                     "8"                     },
-  { "df_wooden_wall.frames",                   "1"                     },
-
-  { "df_refractor",                            "RocksDF.png"           },
-  { "df_refractor.xpos",                       "1"                     },
-  { "df_refractor.ypos",                       "8"                     },
-  { "df_refractor.frames",                     "1"                     },
-
-  { "df_cell",                                 "RocksDF.png"           },
-  { "df_cell.xpos",                            "2"                     },
-  { "df_cell.ypos",                            "8"                     },
-  { "df_cell.frames",                          "1"                     },
-
-  { "df_mine",                                 "RocksDF.png"           },
-  { "df_mine.xpos",                            "4"                     },
-  { "df_mine.ypos",                            "8"                     },
-  { "df_mine.frames",                          "1"                     },
+  { "player_1",                                                "RocksHeroes.png"               },
+  { "player_1.xpos",                                   "0"                             },
+  { "player_1.ypos",                                   "0"                             },
+  { "player_1.frames",                                 "1"                             },
+  { "player_1.down",                                   "RocksHeroes.png"               },
+  { "player_1.down.xpos",                              "0"                             },
+  { "player_1.down.ypos",                              "0"                             },
+  { "player_1.down.frames",                            "1"                             },
+  { "player_1.up",                                     "RocksHeroes.png"               },
+  { "player_1.up.xpos",                                        "4"                             },
+  { "player_1.up.ypos",                                        "0"                             },
+  { "player_1.up.frames",                              "1"                             },
+  { "player_1.left",                                   "RocksHeroes.png"               },
+  { "player_1.left.xpos",                              "0"                             },
+  { "player_1.left.ypos",                              "1"                             },
+  { "player_1.left.frames",                            "1"                             },
+  { "player_1.right",                                  "RocksHeroes.png"               },
+  { "player_1.right.xpos",                             "4"                             },
+  { "player_1.right.ypos",                             "1"                             },
+  { "player_1.right.frames",                           "1"                             },
+  { "player_1.moving.down",                            "RocksHeroes.png"               },
+  { "player_1.moving.down.xpos",                       "0"                             },
+  { "player_1.moving.down.ypos",                       "0"                             },
+  { "player_1.moving.down.frames",                     "4"                             },
+  { "player_1.moving.down.start_frame",                        "1"                             },
+  { "player_1.moving.down.delay",                      "4"                             },
+  { "player_1.moving.up",                              "RocksHeroes.png"               },
+  { "player_1.moving.up.xpos",                         "4"                             },
+  { "player_1.moving.up.ypos",                         "0"                             },
+  { "player_1.moving.up.frames",                       "4"                             },
+  { "player_1.moving.up.start_frame",                  "1"                             },
+  { "player_1.moving.up.delay",                                "4"                             },
+  { "player_1.moving.left",                            "RocksHeroes.png"               },
+  { "player_1.moving.left.xpos",                       "0"                             },
+  { "player_1.moving.left.ypos",                       "1"                             },
+  { "player_1.moving.left.frames",                     "4"                             },
+  { "player_1.moving.left.start_frame",                        "1"                             },
+  { "player_1.moving.left.delay",                      "4"                             },
+  { "player_1.moving.right",                           "RocksHeroes.png"               },
+  { "player_1.moving.right.xpos",                      "4"                             },
+  { "player_1.moving.right.ypos",                      "1"                             },
+  { "player_1.moving.right.frames",                    "4"                             },
+  { "player_1.moving.right.start_frame",               "1"                             },
+  { "player_1.moving.right.delay",                     "4"                             },
+  { "player_1.digging.down",                           "RocksHeroes.png"               },
+  { "player_1.digging.down.xpos",                      "0"                             },
+  { "player_1.digging.down.ypos",                      "0"                             },
+  { "player_1.digging.down.frames",                    "4"                             },
+  { "player_1.digging.down.start_frame",               "1"                             },
+  { "player_1.digging.down.delay",                     "4"                             },
+  { "player_1.digging.up",                             "RocksHeroes.png"               },
+  { "player_1.digging.up.xpos",                                "4"                             },
+  { "player_1.digging.up.ypos",                                "0"                             },
+  { "player_1.digging.up.frames",                      "4"                             },
+  { "player_1.digging.up.start_frame",                 "1"                             },
+  { "player_1.digging.up.delay",                       "4"                             },
+  { "player_1.digging.left",                           "RocksHeroes.png"               },
+  { "player_1.digging.left.xpos",                      "0"                             },
+  { "player_1.digging.left.ypos",                      "1"                             },
+  { "player_1.digging.left.frames",                    "4"                             },
+  { "player_1.digging.left.start_frame",               "1"                             },
+  { "player_1.digging.left.delay",                     "4"                             },
+  { "player_1.digging.right",                          "RocksHeroes.png"               },
+  { "player_1.digging.right.xpos",                     "4"                             },
+  { "player_1.digging.right.ypos",                     "1"                             },
+  { "player_1.digging.right.frames",                   "4"                             },
+  { "player_1.digging.right.start_frame",              "1"                             },
+  { "player_1.digging.right.delay",                    "4"                             },
+  { "player_1.collecting.down",                                "RocksHeroes.png"               },
+  { "player_1.collecting.down.xpos",                   "0"                             },
+  { "player_1.collecting.down.ypos",                   "0"                             },
+  { "player_1.collecting.down.frames",                 "4"                             },
+  { "player_1.collecting.down.start_frame",            "1"                             },
+  { "player_1.collecting.down.delay",                  "4"                             },
+  { "player_1.collecting.up",                          "RocksHeroes.png"               },
+  { "player_1.collecting.up.xpos",                     "4"                             },
+  { "player_1.collecting.up.ypos",                     "0"                             },
+  { "player_1.collecting.up.frames",                   "4"                             },
+  { "player_1.collecting.up.start_frame",              "1"                             },
+  { "player_1.collecting.up.delay",                    "4"                             },
+  { "player_1.collecting.left",                                "RocksHeroes.png"               },
+  { "player_1.collecting.left.xpos",                   "0"                             },
+  { "player_1.collecting.left.ypos",                   "1"                             },
+  { "player_1.collecting.left.frames",                 "4"                             },
+  { "player_1.collecting.left.start_frame",            "1"                             },
+  { "player_1.collecting.left.delay",                  "4"                             },
+  { "player_1.collecting.right",                       "RocksHeroes.png"               },
+  { "player_1.collecting.right.xpos",                  "4"                             },
+  { "player_1.collecting.right.ypos",                  "1"                             },
+  { "player_1.collecting.right.frames",                        "4"                             },
+  { "player_1.collecting.right.start_frame",           "1"                             },
+  { "player_1.collecting.right.delay",                 "4"                             },
+  { "player_1.pushing.down",                           "RocksHeroes.png"               },
+  { "player_1.pushing.down.xpos",                      "0"                             },
+  { "player_1.pushing.down.ypos",                      "0"                             },
+  { "player_1.pushing.down.frames",                    "4"                             },
+  { "player_1.pushing.down.delay",                     "4"                             },
+  { "player_1.pushing.up",                             "RocksHeroes.png"               },
+  { "player_1.pushing.up.xpos",                                "4"                             },
+  { "player_1.pushing.up.ypos",                                "0"                             },
+  { "player_1.pushing.up.frames",                      "4"                             },
+  { "player_1.pushing.up.delay",                       "4"                             },
+  { "player_1.pushing.left",                           "RocksHeroes.png"               },
+  { "player_1.pushing.left.xpos",                      "4"                             },
+  { "player_1.pushing.left.ypos",                      "2"                             },
+  { "player_1.pushing.left.frames",                    "4"                             },
+  { "player_1.pushing.left.delay",                     "4"                             },
+  { "player_1.pushing.right",                          "RocksHeroes.png"               },
+  { "player_1.pushing.right.xpos",                     "0"                             },
+  { "player_1.pushing.right.ypos",                     "2"                             },
+  { "player_1.pushing.right.frames",                   "4"                             },
+  { "player_1.pushing.right.delay",                    "4"                             },
+  { "player_1.snapping.down",                          "RocksHeroes.png"               },
+  { "player_1.snapping.down.xpos",                     "0"                             },
+  { "player_1.snapping.down.ypos",                     "0"                             },
+  { "player_1.snapping.down.frames",                   "1"                             },
+  { "player_1.snapping.up",                            "RocksHeroes.png"               },
+  { "player_1.snapping.up.xpos",                       "4"                             },
+  { "player_1.snapping.up.ypos",                       "0"                             },
+  { "player_1.snapping.up.frames",                     "1"                             },
+  { "player_1.snapping.left",                          "RocksHeroes.png"               },
+  { "player_1.snapping.left.xpos",                     "0"                             },
+  { "player_1.snapping.left.ypos",                     "1"                             },
+  { "player_1.snapping.left.frames",                   "1"                             },
+  { "player_1.snapping.right",                         "RocksHeroes.png"               },
+  { "player_1.snapping.right.xpos",                    "4"                             },
+  { "player_1.snapping.right.ypos",                    "1"                             },
+  { "player_1.snapping.right.frames",                  "1"                             },
+
+  { "player_2",                                                "RocksHeroes.png"               },
+  { "player_2.xpos",                                   "0"                             },
+  { "player_2.ypos",                                   "3"                             },
+  { "player_2.frames",                                 "1"                             },
+  { "player_2.down",                                   "RocksHeroes.png"               },
+  { "player_2.down.xpos",                              "0"                             },
+  { "player_2.down.ypos",                              "3"                             },
+  { "player_2.down.frames",                            "1"                             },
+  { "player_2.up",                                     "RocksHeroes.png"               },
+  { "player_2.up.xpos",                                        "4"                             },
+  { "player_2.up.ypos",                                        "3"                             },
+  { "player_2.up.frames",                              "1"                             },
+  { "player_2.left",                                   "RocksHeroes.png"               },
+  { "player_2.left.xpos",                              "0"                             },
+  { "player_2.left.ypos",                              "4"                             },
+  { "player_2.left.frames",                            "1"                             },
+  { "player_2.right",                                  "RocksHeroes.png"               },
+  { "player_2.right.xpos",                             "4"                             },
+  { "player_2.right.ypos",                             "4"                             },
+  { "player_2.right.frames",                           "1"                             },
+  { "player_2.moving.down",                            "RocksHeroes.png"               },
+  { "player_2.moving.down.xpos",                       "0"                             },
+  { "player_2.moving.down.ypos",                       "3"                             },
+  { "player_2.moving.down.frames",                     "4"                             },
+  { "player_2.moving.down.start_frame",                        "1"                             },
+  { "player_2.moving.down.delay",                      "4"                             },
+  { "player_2.moving.up",                              "RocksHeroes.png"               },
+  { "player_2.moving.up.xpos",                         "4"                             },
+  { "player_2.moving.up.ypos",                         "3"                             },
+  { "player_2.moving.up.frames",                       "4"                             },
+  { "player_2.moving.up.start_frame",                  "1"                             },
+  { "player_2.moving.up.delay",                                "4"                             },
+  { "player_2.moving.left",                            "RocksHeroes.png"               },
+  { "player_2.moving.left.xpos",                       "0"                             },
+  { "player_2.moving.left.ypos",                       "4"                             },
+  { "player_2.moving.left.frames",                     "4"                             },
+  { "player_2.moving.left.start_frame",                        "1"                             },
+  { "player_2.moving.left.delay",                      "4"                             },
+  { "player_2.moving.right",                           "RocksHeroes.png"               },
+  { "player_2.moving.right.xpos",                      "4"                             },
+  { "player_2.moving.right.ypos",                      "4"                             },
+  { "player_2.moving.right.frames",                    "4"                             },
+  { "player_2.moving.right.start_frame",               "1"                             },
+  { "player_2.moving.right.delay",                     "4"                             },
+  { "player_2.digging.down",                           "RocksHeroes.png"               },
+  { "player_2.digging.down.xpos",                      "0"                             },
+  { "player_2.digging.down.ypos",                      "3"                             },
+  { "player_2.digging.down.frames",                    "4"                             },
+  { "player_2.digging.down.start_frame",               "1"                             },
+  { "player_2.digging.down.delay",                     "4"                             },
+  { "player_2.digging.up",                             "RocksHeroes.png"               },
+  { "player_2.digging.up.xpos",                                "4"                             },
+  { "player_2.digging.up.ypos",                                "3"                             },
+  { "player_2.digging.up.frames",                      "4"                             },
+  { "player_2.digging.up.start_frame",                 "1"                             },
+  { "player_2.digging.up.delay",                       "4"                             },
+  { "player_2.digging.left",                           "RocksHeroes.png"               },
+  { "player_2.digging.left.xpos",                      "0"                             },
+  { "player_2.digging.left.ypos",                      "4"                             },
+  { "player_2.digging.left.frames",                    "4"                             },
+  { "player_2.digging.left.start_frame",               "1"                             },
+  { "player_2.digging.left.delay",                     "4"                             },
+  { "player_2.digging.right",                          "RocksHeroes.png"               },
+  { "player_2.digging.right.xpos",                     "4"                             },
+  { "player_2.digging.right.ypos",                     "4"                             },
+  { "player_2.digging.right.frames",                   "4"                             },
+  { "player_2.digging.right.start_frame",              "1"                             },
+  { "player_2.digging.right.delay",                    "4"                             },
+  { "player_2.collecting.down",                                "RocksHeroes.png"               },
+  { "player_2.collecting.down.xpos",                   "0"                             },
+  { "player_2.collecting.down.ypos",                   "3"                             },
+  { "player_2.collecting.down.frames",                 "4"                             },
+  { "player_2.collecting.down.start_frame",            "1"                             },
+  { "player_2.collecting.down.delay",                  "4"                             },
+  { "player_2.collecting.up",                          "RocksHeroes.png"               },
+  { "player_2.collecting.up.xpos",                     "4"                             },
+  { "player_2.collecting.up.ypos",                     "3"                             },
+  { "player_2.collecting.up.frames",                   "4"                             },
+  { "player_2.collecting.up.start_frame",              "1"                             },
+  { "player_2.collecting.up.delay",                    "4"                             },
+  { "player_2.collecting.left",                                "RocksHeroes.png"               },
+  { "player_2.collecting.left.xpos",                   "0"                             },
+  { "player_2.collecting.left.ypos",                   "4"                             },
+  { "player_2.collecting.left.frames",                 "4"                             },
+  { "player_2.collecting.left.start_frame",            "1"                             },
+  { "player_2.collecting.left.delay",                  "4"                             },
+  { "player_2.collecting.right",                       "RocksHeroes.png"               },
+  { "player_2.collecting.right.xpos",                  "4"                             },
+  { "player_2.collecting.right.ypos",                  "4"                             },
+  { "player_2.collecting.right.frames",                        "4"                             },
+  { "player_2.collecting.right.start_frame",           "1"                             },
+  { "player_2.collecting.right.delay",                 "4"                             },
+  { "player_2.pushing.down",                           "RocksHeroes.png"               },
+  { "player_2.pushing.down.xpos",                      "0"                             },
+  { "player_2.pushing.down.ypos",                      "3"                             },
+  { "player_2.pushing.down.frames",                    "4"                             },
+  { "player_2.pushing.down.delay",                     "4"                             },
+  { "player_2.pushing.up",                             "RocksHeroes.png"               },
+  { "player_2.pushing.up.xpos",                                "4"                             },
+  { "player_2.pushing.up.ypos",                                "3"                             },
+  { "player_2.pushing.up.frames",                      "4"                             },
+  { "player_2.pushing.up.delay",                       "4"                             },
+  { "player_2.pushing.left",                           "RocksHeroes.png"               },
+  { "player_2.pushing.left.xpos",                      "4"                             },
+  { "player_2.pushing.left.ypos",                      "5"                             },
+  { "player_2.pushing.left.frames",                    "4"                             },
+  { "player_2.pushing.left.delay",                     "4"                             },
+  { "player_2.pushing.right",                          "RocksHeroes.png"               },
+  { "player_2.pushing.right.xpos",                     "0"                             },
+  { "player_2.pushing.right.ypos",                     "5"                             },
+  { "player_2.pushing.right.frames",                   "4"                             },
+  { "player_2.pushing.right.delay",                    "4"                             },
+  { "player_2.snapping.down",                          "RocksHeroes.png"               },
+  { "player_2.snapping.down.xpos",                     "0"                             },
+  { "player_2.snapping.down.ypos",                     "3"                             },
+  { "player_2.snapping.down.frames",                   "1"                             },
+  { "player_2.snapping.up",                            "RocksHeroes.png"               },
+  { "player_2.snapping.up.xpos",                       "4"                             },
+  { "player_2.snapping.up.ypos",                       "3"                             },
+  { "player_2.snapping.up.frames",                     "1"                             },
+  { "player_2.snapping.left",                          "RocksHeroes.png"               },
+  { "player_2.snapping.left.xpos",                     "0"                             },
+  { "player_2.snapping.left.ypos",                     "4"                             },
+  { "player_2.snapping.left.frames",                   "1"                             },
+  { "player_2.snapping.right",                         "RocksHeroes.png"               },
+  { "player_2.snapping.right.xpos",                    "4"                             },
+  { "player_2.snapping.right.ypos",                    "4"                             },
+  { "player_2.snapping.right.frames",                  "1"                             },
+
+  { "player_3",                                                "RocksHeroes.png"               },
+  { "player_3.xpos",                                   "0"                             },
+  { "player_3.ypos",                                   "6"                             },
+  { "player_3.frames",                                 "1"                             },
+  { "player_3.down",                                   "RocksHeroes.png"               },
+  { "player_3.down.xpos",                              "0"                             },
+  { "player_3.down.ypos",                              "6"                             },
+  { "player_3.down.frames",                            "1"                             },
+  { "player_3.up",                                     "RocksHeroes.png"               },
+  { "player_3.up.xpos",                                        "4"                             },
+  { "player_3.up.ypos",                                        "6"                             },
+  { "player_3.up.frames",                              "1"                             },
+  { "player_3.left",                                   "RocksHeroes.png"               },
+  { "player_3.left.xpos",                              "0"                             },
+  { "player_3.left.ypos",                              "7"                             },
+  { "player_3.left.frames",                            "1"                             },
+  { "player_3.right",                                  "RocksHeroes.png"               },
+  { "player_3.right.xpos",                             "4"                             },
+  { "player_3.right.ypos",                             "7"                             },
+  { "player_3.right.frames",                           "1"                             },
+  { "player_3.moving.down",                            "RocksHeroes.png"               },
+  { "player_3.moving.down.xpos",                       "0"                             },
+  { "player_3.moving.down.ypos",                       "6"                             },
+  { "player_3.moving.down.frames",                     "4"                             },
+  { "player_3.moving.down.start_frame",                        "1"                             },
+  { "player_3.moving.down.delay",                      "4"                             },
+  { "player_3.moving.up",                              "RocksHeroes.png"               },
+  { "player_3.moving.up.xpos",                         "4"                             },
+  { "player_3.moving.up.ypos",                         "6"                             },
+  { "player_3.moving.up.frames",                       "4"                             },
+  { "player_3.moving.up.start_frame",                  "1"                             },
+  { "player_3.moving.up.delay",                                "4"                             },
+  { "player_3.moving.left",                            "RocksHeroes.png"               },
+  { "player_3.moving.left.xpos",                       "0"                             },
+  { "player_3.moving.left.ypos",                       "7"                             },
+  { "player_3.moving.left.frames",                     "4"                             },
+  { "player_3.moving.left.start_frame",                        "1"                             },
+  { "player_3.moving.left.delay",                      "4"                             },
+  { "player_3.moving.right",                           "RocksHeroes.png"               },
+  { "player_3.moving.right.xpos",                      "4"                             },
+  { "player_3.moving.right.ypos",                      "7"                             },
+  { "player_3.moving.right.frames",                    "4"                             },
+  { "player_3.moving.right.start_frame",               "1"                             },
+  { "player_3.moving.right.delay",                     "4"                             },
+  { "player_3.digging.down",                           "RocksHeroes.png"               },
+  { "player_3.digging.down.xpos",                      "0"                             },
+  { "player_3.digging.down.ypos",                      "6"                             },
+  { "player_3.digging.down.frames",                    "4"                             },
+  { "player_3.digging.down.start_frame",               "1"                             },
+  { "player_3.digging.down.delay",                     "4"                             },
+  { "player_3.digging.up",                             "RocksHeroes.png"               },
+  { "player_3.digging.up.xpos",                                "4"                             },
+  { "player_3.digging.up.ypos",                                "6"                             },
+  { "player_3.digging.up.frames",                      "4"                             },
+  { "player_3.digging.up.start_frame",                 "1"                             },
+  { "player_3.digging.up.delay",                       "4"                             },
+  { "player_3.digging.left",                           "RocksHeroes.png"               },
+  { "player_3.digging.left.xpos",                      "0"                             },
+  { "player_3.digging.left.ypos",                      "7"                             },
+  { "player_3.digging.left.frames",                    "4"                             },
+  { "player_3.digging.left.start_frame",               "1"                             },
+  { "player_3.digging.left.delay",                     "4"                             },
+  { "player_3.digging.right",                          "RocksHeroes.png"               },
+  { "player_3.digging.right.xpos",                     "4"                             },
+  { "player_3.digging.right.ypos",                     "7"                             },
+  { "player_3.digging.right.frames",                   "4"                             },
+  { "player_3.digging.right.start_frame",              "1"                             },
+  { "player_3.digging.right.delay",                    "4"                             },
+  { "player_3.collecting.down",                                "RocksHeroes.png"               },
+  { "player_3.collecting.down.xpos",                   "0"                             },
+  { "player_3.collecting.down.ypos",                   "6"                             },
+  { "player_3.collecting.down.frames",                 "4"                             },
+  { "player_3.collecting.down.start_frame",            "1"                             },
+  { "player_3.collecting.down.delay",                  "4"                             },
+  { "player_3.collecting.up",                          "RocksHeroes.png"               },
+  { "player_3.collecting.up.xpos",                     "4"                             },
+  { "player_3.collecting.up.ypos",                     "6"                             },
+  { "player_3.collecting.up.frames",                   "4"                             },
+  { "player_3.collecting.up.start_frame",              "1"                             },
+  { "player_3.collecting.up.delay",                    "4"                             },
+  { "player_3.collecting.left",                                "RocksHeroes.png"               },
+  { "player_3.collecting.left.xpos",                   "0"                             },
+  { "player_3.collecting.left.ypos",                   "7"                             },
+  { "player_3.collecting.left.frames",                 "4"                             },
+  { "player_3.collecting.left.start_frame",            "1"                             },
+  { "player_3.collecting.left.delay",                  "4"                             },
+  { "player_3.collecting.right",                       "RocksHeroes.png"               },
+  { "player_3.collecting.right.xpos",                  "4"                             },
+  { "player_3.collecting.right.ypos",                  "7"                             },
+  { "player_3.collecting.right.frames",                        "4"                             },
+  { "player_3.collecting.right.start_frame",           "1"                             },
+  { "player_3.collecting.right.delay",                 "4"                             },
+  { "player_3.pushing.down",                           "RocksHeroes.png"               },
+  { "player_3.pushing.down.xpos",                      "0"                             },
+  { "player_3.pushing.down.ypos",                      "6"                             },
+  { "player_3.pushing.down.frames",                    "4"                             },
+  { "player_3.pushing.down.delay",                     "4"                             },
+  { "player_3.pushing.up",                             "RocksHeroes.png"               },
+  { "player_3.pushing.up.xpos",                                "4"                             },
+  { "player_3.pushing.up.ypos",                                "6"                             },
+  { "player_3.pushing.up.frames",                      "4"                             },
+  { "player_3.pushing.up.delay",                       "4"                             },
+  { "player_3.pushing.left",                           "RocksHeroes.png"               },
+  { "player_3.pushing.left.xpos",                      "4"                             },
+  { "player_3.pushing.left.ypos",                      "8"                             },
+  { "player_3.pushing.left.frames",                    "4"                             },
+  { "player_3.pushing.left.delay",                     "4"                             },
+  { "player_3.pushing.right",                          "RocksHeroes.png"               },
+  { "player_3.pushing.right.xpos",                     "0"                             },
+  { "player_3.pushing.right.ypos",                     "8"                             },
+  { "player_3.pushing.right.frames",                   "4"                             },
+  { "player_3.pushing.right.delay",                    "4"                             },
+  { "player_3.snapping.down",                          "RocksHeroes.png"               },
+  { "player_3.snapping.down.xpos",                     "0"                             },
+  { "player_3.snapping.down.ypos",                     "6"                             },
+  { "player_3.snapping.down.frames",                   "1"                             },
+  { "player_3.snapping.up",                            "RocksHeroes.png"               },
+  { "player_3.snapping.up.xpos",                       "4"                             },
+  { "player_3.snapping.up.ypos",                       "6"                             },
+  { "player_3.snapping.up.frames",                     "1"                             },
+  { "player_3.snapping.left",                          "RocksHeroes.png"               },
+  { "player_3.snapping.left.xpos",                     "0"                             },
+  { "player_3.snapping.left.ypos",                     "7"                             },
+  { "player_3.snapping.left.frames",                   "1"                             },
+  { "player_3.snapping.right",                         "RocksHeroes.png"               },
+  { "player_3.snapping.right.xpos",                    "4"                             },
+  { "player_3.snapping.right.ypos",                    "7"                             },
+  { "player_3.snapping.right.frames",                  "1"                             },
+
+  { "player_4",                                                "RocksHeroes.png"               },
+  { "player_4.xpos",                                   "0"                             },
+  { "player_4.ypos",                                   "9"                             },
+  { "player_4.frames",                                 "1"                             },
+  { "player_4.down",                                   "RocksHeroes.png"               },
+  { "player_4.down.xpos",                              "0"                             },
+  { "player_4.down.ypos",                              "9"                             },
+  { "player_4.down.frames",                            "1"                             },
+  { "player_4.up",                                     "RocksHeroes.png"               },
+  { "player_4.up.xpos",                                        "4"                             },
+  { "player_4.up.ypos",                                        "9"                             },
+  { "player_4.up.frames",                              "1"                             },
+  { "player_4.left",                                   "RocksHeroes.png"               },
+  { "player_4.left.xpos",                              "0"                             },
+  { "player_4.left.ypos",                              "10"                            },
+  { "player_4.left.frames",                            "1"                             },
+  { "player_4.right",                                  "RocksHeroes.png"               },
+  { "player_4.right.xpos",                             "4"                             },
+  { "player_4.right.ypos",                             "10"                            },
+  { "player_4.right.frames",                           "1"                             },
+  { "player_4.moving.down",                            "RocksHeroes.png"               },
+  { "player_4.moving.down.xpos",                       "0"                             },
+  { "player_4.moving.down.ypos",                       "9"                             },
+  { "player_4.moving.down.frames",                     "4"                             },
+  { "player_4.moving.down.start_frame",                        "1"                             },
+  { "player_4.moving.down.delay",                      "4"                             },
+  { "player_4.moving.up",                              "RocksHeroes.png"               },
+  { "player_4.moving.up.xpos",                         "4"                             },
+  { "player_4.moving.up.ypos",                         "9"                             },
+  { "player_4.moving.up.frames",                       "4"                             },
+  { "player_4.moving.up.start_frame",                  "1"                             },
+  { "player_4.moving.up.delay",                                "4"                             },
+  { "player_4.moving.left",                            "RocksHeroes.png"               },
+  { "player_4.moving.left.xpos",                       "0"                             },
+  { "player_4.moving.left.ypos",                       "10"                            },
+  { "player_4.moving.left.frames",                     "4"                             },
+  { "player_4.moving.left.start_frame",                        "1"                             },
+  { "player_4.moving.left.delay",                      "4"                             },
+  { "player_4.moving.right",                           "RocksHeroes.png"               },
+  { "player_4.moving.right.xpos",                      "4"                             },
+  { "player_4.moving.right.ypos",                      "10"                            },
+  { "player_4.moving.right.frames",                    "4"                             },
+  { "player_4.moving.right.start_frame",               "1"                             },
+  { "player_4.moving.right.delay",                     "4"                             },
+  { "player_4.digging.down",                           "RocksHeroes.png"               },
+  { "player_4.digging.down.xpos",                      "0"                             },
+  { "player_4.digging.down.ypos",                      "9"                             },
+  { "player_4.digging.down.frames",                    "4"                             },
+  { "player_4.digging.down.start_frame",               "1"                             },
+  { "player_4.digging.down.delay",                     "4"                             },
+  { "player_4.digging.up",                             "RocksHeroes.png"               },
+  { "player_4.digging.up.xpos",                                "4"                             },
+  { "player_4.digging.up.ypos",                                "9"                             },
+  { "player_4.digging.up.frames",                      "4"                             },
+  { "player_4.digging.up.start_frame",                 "1"                             },
+  { "player_4.digging.up.delay",                       "4"                             },
+  { "player_4.digging.left",                           "RocksHeroes.png"               },
+  { "player_4.digging.left.xpos",                      "0"                             },
+  { "player_4.digging.left.ypos",                      "10"                            },
+  { "player_4.digging.left.frames",                    "4"                             },
+  { "player_4.digging.left.start_frame",               "1"                             },
+  { "player_4.digging.left.delay",                     "4"                             },
+  { "player_4.digging.right",                          "RocksHeroes.png"               },
+  { "player_4.digging.right.xpos",                     "4"                             },
+  { "player_4.digging.right.ypos",                     "10"                            },
+  { "player_4.digging.right.frames",                   "4"                             },
+  { "player_4.digging.right.start_frame",              "1"                             },
+  { "player_4.digging.right.delay",                    "4"                             },
+  { "player_4.collecting.down",                                "RocksHeroes.png"               },
+  { "player_4.collecting.down.xpos",                   "0"                             },
+  { "player_4.collecting.down.ypos",                   "9"                             },
+  { "player_4.collecting.down.frames",                 "4"                             },
+  { "player_4.collecting.down.start_frame",            "1"                             },
+  { "player_4.collecting.down.delay",                  "4"                             },
+  { "player_4.collecting.up",                          "RocksHeroes.png"               },
+  { "player_4.collecting.up.xpos",                     "4"                             },
+  { "player_4.collecting.up.ypos",                     "9"                             },
+  { "player_4.collecting.up.frames",                   "4"                             },
+  { "player_4.collecting.up.start_frame",              "1"                             },
+  { "player_4.collecting.up.delay",                    "4"                             },
+  { "player_4.collecting.left",                                "RocksHeroes.png"               },
+  { "player_4.collecting.left.xpos",                   "0"                             },
+  { "player_4.collecting.left.ypos",                   "10"                            },
+  { "player_4.collecting.left.frames",                 "4"                             },
+  { "player_4.collecting.left.start_frame",            "1"                             },
+  { "player_4.collecting.left.delay",                  "4"                             },
+  { "player_4.collecting.right",                       "RocksHeroes.png"               },
+  { "player_4.collecting.right.xpos",                  "4"                             },
+  { "player_4.collecting.right.ypos",                  "10"                            },
+  { "player_4.collecting.right.frames",                        "4"                             },
+  { "player_4.collecting.right.start_frame",           "1"                             },
+  { "player_4.collecting.right.delay",                 "4"                             },
+  { "player_4.pushing.down",                           "RocksHeroes.png"               },
+  { "player_4.pushing.down.xpos",                      "0"                             },
+  { "player_4.pushing.down.ypos",                      "9"                             },
+  { "player_4.pushing.down.frames",                    "4"                             },
+  { "player_4.pushing.down.delay",                     "4"                             },
+  { "player_4.pushing.up",                             "RocksHeroes.png"               },
+  { "player_4.pushing.up.xpos",                                "4"                             },
+  { "player_4.pushing.up.ypos",                                "9"                             },
+  { "player_4.pushing.up.frames",                      "4"                             },
+  { "player_4.pushing.up.delay",                       "4"                             },
+  { "player_4.pushing.left",                           "RocksHeroes.png"               },
+  { "player_4.pushing.left.xpos",                      "4"                             },
+  { "player_4.pushing.left.ypos",                      "11"                            },
+  { "player_4.pushing.left.frames",                    "4"                             },
+  { "player_4.pushing.left.delay",                     "4"                             },
+  { "player_4.pushing.right",                          "RocksHeroes.png"               },
+  { "player_4.pushing.right.xpos",                     "0"                             },
+  { "player_4.pushing.right.ypos",                     "11"                            },
+  { "player_4.pushing.right.frames",                   "4"                             },
+  { "player_4.pushing.right.delay",                    "4"                             },
+  { "player_4.snapping.down",                          "RocksHeroes.png"               },
+  { "player_4.snapping.down.xpos",                     "0"                             },
+  { "player_4.snapping.down.ypos",                     "9"                             },
+  { "player_4.snapping.down.frames",                   "1"                             },
+  { "player_4.snapping.up",                            "RocksHeroes.png"               },
+  { "player_4.snapping.up.xpos",                       "4"                             },
+  { "player_4.snapping.up.ypos",                       "9"                             },
+  { "player_4.snapping.up.frames",                     "1"                             },
+  { "player_4.snapping.left",                          "RocksHeroes.png"               },
+  { "player_4.snapping.left.xpos",                     "0"                             },
+  { "player_4.snapping.left.ypos",                     "10"                            },
+  { "player_4.snapping.left.frames",                   "1"                             },
+  { "player_4.snapping.right",                         "RocksHeroes.png"               },
+  { "player_4.snapping.right.xpos",                    "4"                             },
+  { "player_4.snapping.right.ypos",                    "10"                            },
+  { "player_4.snapping.right.frames",                  "1"                             },
+
+  { "[default].exploding",                             "RocksElements.png"             },
+  { "[default].exploding.xpos",                                "0"                             },
+  { "[default].exploding.ypos",                                "4"                             },
+  { "[default].exploding.frames",                      "8"                             },
+  { "[default].exploding.delay",                       "2"                             },
+  { "[default].exploding.anim_mode",                   "linear"                        },
+
+  { "twinkle_blue",                                    "RocksHeroes.png"               },
+  { "twinkle_blue.xpos",                               "9"                             },
+  { "twinkle_blue.ypos",                               "11"                            },
+  { "twinkle_blue.frames",                             "3"                             },
+  { "twinkle_blue.delay",                              "2"                             },
+  { "twinkle_blue.anim_mode",                          "pingpong"                      },
+  { "twinkle_blue.global_sync",                                "false"                         },
+  { "twinkle_white",                                   "RocksHeroes.png"               },
+  { "twinkle_white.xpos",                              "13"                            },
+  { "twinkle_white.ypos",                              "11"                            },
+  { "twinkle_white.frames",                            "3"                             },
+  { "twinkle_white.delay",                             "2"                             },
+  { "twinkle_white.anim_mode",                         "pingpong"                      },
+  { "twinkle_white.global_sync",                       "false"                         },
+
+  { "steelwall_topleft",                               "RocksElements.png"             },
+  { "steelwall_topleft.xpos",                          "4"                             },
+  { "steelwall_topleft.ypos",                          "0"                             },
+  { "steelwall_topleft.frames",                                "1"                             },
+  { "steelwall_topright",                              "RocksElements.png"             },
+  { "steelwall_topright.xpos",                         "4"                             },
+  { "steelwall_topright.ypos",                         "0"                             },
+  { "steelwall_topright.frames",                       "1"                             },
+  { "steelwall_bottomleft",                            "RocksElements.png"             },
+  { "steelwall_bottomleft.xpos",                       "4"                             },
+  { "steelwall_bottomleft.ypos",                       "0"                             },
+  { "steelwall_bottomleft.frames",                     "1"                             },
+  { "steelwall_bottomright",                           "RocksElements.png"             },
+  { "steelwall_bottomright.xpos",                      "4"                             },
+  { "steelwall_bottomright.ypos",                      "0"                             },
+  { "steelwall_bottomright.frames",                    "1"                             },
+  { "steelwall_horizontal",                            "RocksElements.png"             },
+  { "steelwall_horizontal.xpos",                       "4"                             },
+  { "steelwall_horizontal.ypos",                       "0"                             },
+  { "steelwall_horizontal.frames",                     "1"                             },
+  { "steelwall_vertical",                              "RocksElements.png"             },
+  { "steelwall_vertical.xpos",                         "4"                             },
+  { "steelwall_vertical.ypos",                         "0"                             },
+  { "steelwall_vertical.frames",                       "1"                             },
+
+  { "steelwall_topleft.EDITOR",                                "RocksElements.png"             },
+  { "steelwall_topleft.EDITOR.xpos",                   "0"                             },
+  { "steelwall_topleft.EDITOR.ypos",                   "13"                            },
+  { "steelwall_topright.EDITOR",                       "RocksElements.png"             },
+  { "steelwall_topright.EDITOR.xpos",                  "1"                             },
+  { "steelwall_topright.EDITOR.ypos",                  "13"                            },
+  { "steelwall_bottomleft.EDITOR",                     "RocksElements.png"             },
+  { "steelwall_bottomleft.EDITOR.xpos",                        "2"                             },
+  { "steelwall_bottomleft.EDITOR.ypos",                        "13"                            },
+  { "steelwall_bottomright.EDITOR",                    "RocksElements.png"             },
+  { "steelwall_bottomright.EDITOR.xpos",               "3"                             },
+  { "steelwall_bottomright.EDITOR.ypos",               "13"                            },
+  { "steelwall_horizontal.EDITOR",                     "RocksElements.png"             },
+  { "steelwall_horizontal.EDITOR.xpos",                        "4"                             },
+  { "steelwall_horizontal.EDITOR.ypos",                        "13"                            },
+  { "steelwall_vertical.EDITOR",                       "RocksElements.png"             },
+  { "steelwall_vertical.EDITOR.xpos",                  "5"                             },
+  { "steelwall_vertical.EDITOR.ypos",                  "13"                            },
+
+  { "invisible_steelwall_topleft",                     "RocksSP.png"                   },
+  { "invisible_steelwall_topleft.xpos",                        "0"                             },
+  { "invisible_steelwall_topleft.ypos",                        "0"                             },
+  { "invisible_steelwall_topleft.frames",              "1"                             },
+  { "invisible_steelwall_topright",                    "RocksSP.png"                   },
+  { "invisible_steelwall_topright.xpos",               "0"                             },
+  { "invisible_steelwall_topright.ypos",               "0"                             },
+  { "invisible_steelwall_topright.frames",             "1"                             },
+  { "invisible_steelwall_bottomleft",                  "RocksSP.png"                   },
+  { "invisible_steelwall_bottomleft.xpos",             "0"                             },
+  { "invisible_steelwall_bottomleft.ypos",             "0"                             },
+  { "invisible_steelwall_bottomleft.frames",           "1"                             },
+  { "invisible_steelwall_bottomright",                 "RocksSP.png"                   },
+  { "invisible_steelwall_bottomright.xpos",            "0"                             },
+  { "invisible_steelwall_bottomright.ypos",            "0"                             },
+  { "invisible_steelwall_bottomright.frames",          "1"                             },
+  { "invisible_steelwall_horizontal",                  "RocksSP.png"                   },
+  { "invisible_steelwall_horizontal.xpos",             "0"                             },
+  { "invisible_steelwall_horizontal.ypos",             "0"                             },
+  { "invisible_steelwall_horizontal.frames",           "1"                             },
+  { "invisible_steelwall_vertical",                    "RocksSP.png"                   },
+  { "invisible_steelwall_vertical.xpos",               "0"                             },
+  { "invisible_steelwall_vertical.ypos",               "0"                             },
+  { "invisible_steelwall_vertical.frames",             "1"                             },
+
+  { "invisible_steelwall_topleft.EDITOR",              "RocksElements.png"             },
+  { "invisible_steelwall_topleft.EDITOR.xpos",         "6"                             },
+  { "invisible_steelwall_topleft.EDITOR.ypos",         "13"                            },
+  { "invisible_steelwall_topright.EDITOR",             "RocksElements.png"             },
+  { "invisible_steelwall_topright.EDITOR.xpos",                "7"                             },
+  { "invisible_steelwall_topright.EDITOR.ypos",                "13"                            },
+  { "invisible_steelwall_bottomleft.EDITOR",           "RocksElements.png"             },
+  { "invisible_steelwall_bottomleft.EDITOR.xpos",      "8"                             },
+  { "invisible_steelwall_bottomleft.EDITOR.ypos",      "13"                            },
+  { "invisible_steelwall_bottomright.EDITOR",          "RocksElements.png"             },
+  { "invisible_steelwall_bottomright.EDITOR.xpos",     "9"                             },
+  { "invisible_steelwall_bottomright.EDITOR.ypos",     "13"                            },
+  { "invisible_steelwall_horizontal.EDITOR",           "RocksElements.png"             },
+  { "invisible_steelwall_horizontal.EDITOR.xpos",      "10"                            },
+  { "invisible_steelwall_horizontal.EDITOR.ypos",      "13"                            },
+  { "invisible_steelwall_vertical.EDITOR",             "RocksElements.png"             },
+  { "invisible_steelwall_vertical.EDITOR.xpos",                "11"                            },
+  { "invisible_steelwall_vertical.EDITOR.ypos",                "13"                            },
+
+  { "arrow_left",                                      "RocksDC.png"                   },
+  { "arrow_left.xpos",                                 "8"                             },
+  { "arrow_left.ypos",                                 "8"                             },
+  { "arrow_left.frames",                               "1"                             },
+  { "arrow_right",                                     "RocksDC.png"                   },
+  { "arrow_right.xpos",                                        "9"                             },
+  { "arrow_right.ypos",                                        "8"                             },
+  { "arrow_right.frames",                              "1"                             },
+  { "arrow_up",                                                "RocksDC.png"                   },
+  { "arrow_up.xpos",                                   "10"                            },
+  { "arrow_up.ypos",                                   "8"                             },
+  { "arrow_up.frames",                                 "1"                             },
+  { "arrow_down",                                      "RocksDC.png"                   },
+  { "arrow_down.xpos",                                 "11"                            },
+  { "arrow_down.ypos",                                 "8"                             },
+  { "arrow_down.frames",                               "1"                             },
+
+  { "unknown",                                         "RocksFontEM.png"               },
+  { "unknown.xpos",                                    "15"                            },
+  { "unknown.ypos",                                    "1"                             },
+  { "unknown.frames",                                  "1"                             },
+
+  { "trigger_element",                                 "RocksDC.png"                   },
+  { "trigger_element.xpos",                            "15"                            },
+  { "trigger_element.ypos",                            "14"                            },
+  { "trigger_element.frames",                          "1"                             },
+
+  { "trigger_player",                                  "RocksDC.png"                   },
+  { "trigger_player.xpos",                             "15"                            },
+  { "trigger_player.ypos",                             "13"                            },
+  { "trigger_player.frames",                           "1"                             },
+
+  { "trigger_ce_value",                                        "RocksDC.png"                   },
+  { "trigger_ce_value.xpos",                           "15"                            },
+  { "trigger_ce_value.ypos",                           "11"                            },
+  { "trigger_ce_value.frames",                         "1"                             },
+
+  { "trigger_ce_score",                                        "RocksDC.png"                   },
+  { "trigger_ce_score.xpos",                           "15"                            },
+  { "trigger_ce_score.ypos",                           "12"                            },
+  { "trigger_ce_score.frames",                         "1"                             },
+
+  { "current_ce_value",                                        "RocksDC.png"                   },
+  { "current_ce_value.xpos",                           "14"                            },
+  { "current_ce_value.ypos",                           "11"                            },
+  { "current_ce_value.frames",                         "1"                             },
+
+  { "current_ce_score",                                        "RocksDC.png"                   },
+  { "current_ce_score.xpos",                           "14"                            },
+  { "current_ce_score.ypos",                           "12"                            },
+  { "current_ce_score.frames",                         "1"                             },
+
+  { "prev_ce_1",                                       "RocksMore.png"                 },
+  { "prev_ce_1.xpos",                                  "0"                             },
+  { "prev_ce_1.ypos",                                  "7"                             },
+  { "prev_ce_1.frames",                                        "1"                             },
+
+  { "prev_ce_2",                                       "RocksMore.png"                 },
+  { "prev_ce_2.xpos",                                  "1"                             },
+  { "prev_ce_2.ypos",                                  "7"                             },
+  { "prev_ce_2.frames",                                        "1"                             },
+
+  { "prev_ce_3",                                       "RocksMore.png"                 },
+  { "prev_ce_3.xpos",                                  "2"                             },
+  { "prev_ce_3.ypos",                                  "7"                             },
+  { "prev_ce_3.frames",                                        "1"                             },
+
+  { "prev_ce_4",                                       "RocksMore.png"                 },
+  { "prev_ce_4.xpos",                                  "3"                             },
+  { "prev_ce_4.ypos",                                  "7"                             },
+  { "prev_ce_4.frames",                                        "1"                             },
+
+  { "prev_ce_5",                                       "RocksMore.png"                 },
+  { "prev_ce_5.xpos",                                  "4"                             },
+  { "prev_ce_5.ypos",                                  "7"                             },
+  { "prev_ce_5.frames",                                        "1"                             },
+
+  { "prev_ce_6",                                       "RocksMore.png"                 },
+  { "prev_ce_6.xpos",                                  "5"                             },
+  { "prev_ce_6.ypos",                                  "7"                             },
+  { "prev_ce_6.frames",                                        "1"                             },
+
+  { "prev_ce_7",                                       "RocksMore.png"                 },
+  { "prev_ce_7.xpos",                                  "6"                             },
+  { "prev_ce_7.ypos",                                  "7"                             },
+  { "prev_ce_7.frames",                                        "1"                             },
+
+  { "prev_ce_8",                                       "RocksMore.png"                 },
+  { "prev_ce_8.xpos",                                  "7"                             },
+  { "prev_ce_8.ypos",                                  "7"                             },
+  { "prev_ce_8.frames",                                        "1"                             },
+
+  { "next_ce_1",                                       "RocksMore.png"                 },
+  { "next_ce_1.xpos",                                  "0"                             },
+  { "next_ce_1.ypos",                                  "8"                             },
+  { "next_ce_1.frames",                                        "1"                             },
+
+  { "next_ce_2",                                       "RocksMore.png"                 },
+  { "next_ce_2.xpos",                                  "1"                             },
+  { "next_ce_2.ypos",                                  "8"                             },
+  { "next_ce_2.frames",                                        "1"                             },
+
+  { "next_ce_3",                                       "RocksMore.png"                 },
+  { "next_ce_3.xpos",                                  "2"                             },
+  { "next_ce_3.ypos",                                  "8"                             },
+  { "next_ce_3.frames",                                        "1"                             },
+
+  { "next_ce_4",                                       "RocksMore.png"                 },
+  { "next_ce_4.xpos",                                  "3"                             },
+  { "next_ce_4.ypos",                                  "8"                             },
+  { "next_ce_4.frames",                                        "1"                             },
+
+  { "next_ce_5",                                       "RocksMore.png"                 },
+  { "next_ce_5.xpos",                                  "4"                             },
+  { "next_ce_5.ypos",                                  "8"                             },
+  { "next_ce_5.frames",                                        "1"                             },
+
+  { "next_ce_6",                                       "RocksMore.png"                 },
+  { "next_ce_6.xpos",                                  "5"                             },
+  { "next_ce_6.ypos",                                  "8"                             },
+  { "next_ce_6.frames",                                        "1"                             },
+
+  { "next_ce_7",                                       "RocksMore.png"                 },
+  { "next_ce_7.xpos",                                  "6"                             },
+  { "next_ce_7.ypos",                                  "8"                             },
+  { "next_ce_7.frames",                                        "1"                             },
+
+  { "next_ce_8",                                       "RocksMore.png"                 },
+  { "next_ce_8.xpos",                                  "7"                             },
+  { "next_ce_8.ypos",                                  "8"                             },
+  { "next_ce_8.frames",                                        "1"                             },
+
+  { "self",                                            "RocksMore.png"                 },
+  { "self.xpos",                                       "8"                             },
+  { "self.ypos",                                       "7"                             },
+  { "self.frames",                                     "1"                             },
+
+  { "any_element",                                     "RocksMore.png"                 },
+  { "any_element.xpos",                                        "9"                             },
+  { "any_element.ypos",                                        "7"                             },
+  { "any_element.frames",                              "1"                             },
+
+  { "emc_key_5",                                       "RocksEMC.png"                  },
+  { "emc_key_5.xpos",                                  "0"                             },
+  { "emc_key_5.ypos",                                  "5"                             },
+  { "emc_key_5.frames",                                        "1"                             },
+  { "emc_key_5.collecting",                            "RocksCollect.png"              },
+  { "emc_key_5.collecting.xpos",                       "7"                             },
+  { "emc_key_5.collecting.ypos",                       "12"                            },
+  { "emc_key_5.collecting.frames",                     "7"                             },
+  { "emc_key_5.collecting.anim_mode",                  "linear"                        },
+  { "emc_key_6",                                       "RocksEMC.png"                  },
+  { "emc_key_6.xpos",                                  "1"                             },
+  { "emc_key_6.ypos",                                  "5"                             },
+  { "emc_key_6.frames",                                        "1"                             },
+  { "emc_key_6.collecting",                            "RocksCollect.png"              },
+  { "emc_key_6.collecting.xpos",                       "7"                             },
+  { "emc_key_6.collecting.ypos",                       "13"                            },
+  { "emc_key_6.collecting.frames",                     "7"                             },
+  { "emc_key_6.collecting.anim_mode",                  "linear"                        },
+  { "emc_key_7",                                       "RocksEMC.png"                  },
+  { "emc_key_7.xpos",                                  "2"                             },
+  { "emc_key_7.ypos",                                  "5"                             },
+  { "emc_key_7.frames",                                        "1"                             },
+  { "emc_key_7.collecting",                            "RocksCollect.png"              },
+  { "emc_key_7.collecting.xpos",                       "7"                             },
+  { "emc_key_7.collecting.ypos",                       "14"                            },
+  { "emc_key_7.collecting.frames",                     "7"                             },
+  { "emc_key_7.collecting.anim_mode",                  "linear"                        },
+  { "emc_key_8",                                       "RocksEMC.png"                  },
+  { "emc_key_8.xpos",                                  "3"                             },
+  { "emc_key_8.ypos",                                  "5"                             },
+  { "emc_key_8.frames",                                        "1"                             },
+  { "emc_key_8.collecting",                            "RocksCollect.png"              },
+  { "emc_key_8.collecting.xpos",                       "7"                             },
+  { "emc_key_8.collecting.ypos",                       "15"                            },
+  { "emc_key_8.collecting.frames",                     "7"                             },
+  { "emc_key_8.collecting.anim_mode",                  "linear"                        },
+
+  { "emc_gate_5",                                      "RocksEMC.png"                  },
+  { "emc_gate_5.xpos",                                 "0"                             },
+  { "emc_gate_5.ypos",                                 "6"                             },
+  { "emc_gate_5.frames",                               "1"                             },
+  { "emc_gate_6",                                      "RocksEMC.png"                  },
+  { "emc_gate_6.xpos",                                 "1"                             },
+  { "emc_gate_6.ypos",                                 "6"                             },
+  { "emc_gate_6.frames",                               "1"                             },
+  { "emc_gate_7",                                      "RocksEMC.png"                  },
+  { "emc_gate_7.xpos",                                 "2"                             },
+  { "emc_gate_7.ypos",                                 "6"                             },
+  { "emc_gate_7.frames",                               "1"                             },
+  { "emc_gate_8",                                      "RocksEMC.png"                  },
+  { "emc_gate_8.xpos",                                 "3"                             },
+  { "emc_gate_8.ypos",                                 "6"                             },
+  { "emc_gate_8.frames",                               "1"                             },
+  { "emc_gate_5_gray",                                 "RocksEMC.png"                  },
+  { "emc_gate_5_gray.xpos",                            "4"                             },
+  { "emc_gate_5_gray.ypos",                            "7"                             },
+  { "emc_gate_5_gray.frames",                          "1"                             },
+  { "emc_gate_5_gray.EDITOR",                          "RocksEMC.png"                  },
+  { "emc_gate_5_gray.EDITOR.xpos",                     "0"                             },
+  { "emc_gate_5_gray.EDITOR.ypos",                     "7"                             },
+  { "emc_gate_5_gray.active",                          "RocksEMC.png"                  },
+  { "emc_gate_5_gray.active.xpos",                     "0"                             },
+  { "emc_gate_5_gray.active.ypos",                     "6"                             },
+  { "emc_gate_5_gray.active.frames",                   "1"                             },
+  { "emc_gate_6_gray",                                 "RocksEMC.png"                  },
+  { "emc_gate_6_gray.xpos",                            "4"                             },
+  { "emc_gate_6_gray.ypos",                            "7"                             },
+  { "emc_gate_6_gray.frames",                          "1"                             },
+  { "emc_gate_6_gray.EDITOR",                          "RocksEMC.png"                  },
+  { "emc_gate_6_gray.EDITOR.xpos",                     "1"                             },
+  { "emc_gate_6_gray.EDITOR.ypos",                     "7"                             },
+  { "emc_gate_6_gray.active",                          "RocksEMC.png"                  },
+  { "emc_gate_6_gray.active.xpos",                     "1"                             },
+  { "emc_gate_6_gray.active.ypos",                     "6"                             },
+  { "emc_gate_6_gray.active.frames",                   "1"                             },
+  { "emc_gate_7_gray",                                 "RocksEMC.png"                  },
+  { "emc_gate_7_gray.xpos",                            "4"                             },
+  { "emc_gate_7_gray.ypos",                            "7"                             },
+  { "emc_gate_7_gray.frames",                          "1"                             },
+  { "emc_gate_7_gray.EDITOR",                          "RocksEMC.png"                  },
+  { "emc_gate_7_gray.EDITOR.xpos",                     "2"                             },
+  { "emc_gate_7_gray.EDITOR.ypos",                     "7"                             },
+  { "emc_gate_7_gray.active",                          "RocksEMC.png"                  },
+  { "emc_gate_7_gray.active.xpos",                     "2"                             },
+  { "emc_gate_7_gray.active.ypos",                     "6"                             },
+  { "emc_gate_7_gray.active.frames",                   "1"                             },
+  { "emc_gate_8_gray",                                 "RocksEMC.png"                  },
+  { "emc_gate_8_gray.xpos",                            "4"                             },
+  { "emc_gate_8_gray.ypos",                            "7"                             },
+  { "emc_gate_8_gray.frames",                          "1"                             },
+  { "emc_gate_8_gray.EDITOR",                          "RocksEMC.png"                  },
+  { "emc_gate_8_gray.EDITOR.xpos",                     "3"                             },
+  { "emc_gate_8_gray.EDITOR.ypos",                     "7"                             },
+  { "emc_gate_8_gray.active",                          "RocksEMC.png"                  },
+  { "emc_gate_8_gray.active.xpos",                     "3"                             },
+  { "emc_gate_8_gray.active.ypos",                     "6"                             },
+  { "emc_gate_8_gray.active.frames",                   "1"                             },
+
+  { "emc_android",                                     "RocksEMC.png"                  },
+  { "emc_android.xpos",                                        "0"                             },
+  { "emc_android.ypos",                                        "8"                             },
+  { "emc_android.frames",                              "8"                             },
+  { "emc_android.delay",                               "2"                             },
+
+  { "emc_android.shrinking.upleft",                    "RocksEMC.png"                  },
+  { "emc_android.shrinking.upleft.xpos",               "1"                             },
+  { "emc_android.shrinking.upleft.ypos",               "11"                            },
+  { "emc_android.shrinking.upleft.frames",             "8"                             },
+  { "emc_android.shrinking.upleft.anim_mode",          "linear"                        },
+
+  { "emc_android.growing.downright",                   "RocksEMC.png"                  },
+  { "emc_android.growing.downright.xpos",              "0"                             },
+  { "emc_android.growing.downright.ypos",              "11"                            },
+  { "emc_android.growing.downright.frames",            "8"                             },
+  { "emc_android.growing.downright.anim_mode",         "linear,reverse"                },
+
+  { "emc_android.shrinking.downleft",                  "RocksEMC.png"                  },
+  { "emc_android.shrinking.downleft.xpos",             "1"                             },
+  { "emc_android.shrinking.downleft.ypos",             "12"                            },
+  { "emc_android.shrinking.downleft.frames",           "8"                             },
+  { "emc_android.shrinking.downleft.anim_mode",                "linear"                        },
+
+  { "emc_android.growing.upright",                     "RocksEMC.png"                  },
+  { "emc_android.growing.upright.xpos",                        "0"                             },
+  { "emc_android.growing.upright.ypos",                        "12"                            },
+  { "emc_android.growing.upright.frames",              "8"                             },
+  { "emc_android.growing.upright.anim_mode",           "linear,reverse"                },
+
+  { "emc_android.shrinking.upright",                   "RocksEMC.png"                  },
+  { "emc_android.shrinking.upright.xpos",              "1"                             },
+  { "emc_android.shrinking.upright.ypos",              "13"                            },
+  { "emc_android.shrinking.upright.frames",            "8"                             },
+  { "emc_android.shrinking.upright.anim_mode",         "linear"                        },
+
+  { "emc_android.growing.downleft",                    "RocksEMC.png"                  },
+  { "emc_android.growing.downleft.xpos",               "0"                             },
+  { "emc_android.growing.downleft.ypos",               "13"                            },
+  { "emc_android.growing.downleft.frames",             "8"                             },
+  { "emc_android.growing.downleft.anim_mode",          "linear,reverse"                },
+
+  { "emc_android.shrinking.downright",                 "RocksEMC.png"                  },
+  { "emc_android.shrinking.downright.xpos",            "1"                             },
+  { "emc_android.shrinking.downright.ypos",            "14"                            },
+  { "emc_android.shrinking.downright.frames",          "8"                             },
+  { "emc_android.shrinking.downright.anim_mode",       "linear"                        },
+
+  { "emc_android.growing.upleft",                      "RocksEMC.png"                  },
+  { "emc_android.growing.upleft.xpos",                 "0"                             },
+  { "emc_android.growing.upleft.ypos",                 "14"                            },
+  { "emc_android.growing.upleft.frames",               "8"                             },
+  { "emc_android.growing.upleft.anim_mode",            "linear,reverse"                },
+
+  { "emc_grass",                                       "RocksEMC.png"                  },
+  { "emc_grass.xpos",                                  "0"                             },
+  { "emc_grass.ypos",                                  "4"                             },
+  { "emc_grass.frames",                                        "1"                             },
+  { "emc_grass.CRUMBLED",                              "RocksEMC.png"                  },
+  { "emc_grass.CRUMBLED.xpos",                         "1"                             },
+  { "emc_grass.CRUMBLED.ypos",                         "4"                             },
+  { "emc_grass.CRUMBLED.frames",                       "1"                             },
+  { "emc_grass.digging.left",                          "RocksEMC.png"                  },
+  { "emc_grass.digging.left.xpos",                     "6"                             },
+  { "emc_grass.digging.left.ypos",                     "0"                             },
+  { "emc_grass.digging.left.frames",                   "3"                             },
+  { "emc_grass.digging.left.delay",                    "2"                             },
+  { "emc_grass.digging.left.anim_mode",                        "linear"                        },
+  { "emc_grass.digging.right",                         "RocksEMC.png"                  },
+  { "emc_grass.digging.right.xpos",                    "9"                             },
+  { "emc_grass.digging.right.ypos",                    "0"                             },
+  { "emc_grass.digging.right.frames",                  "3"                             },
+  { "emc_grass.digging.right.delay",                   "2"                             },
+  { "emc_grass.digging.right.anim_mode",               "linear"                        },
+  { "emc_grass.digging.up",                            "RocksEMC.png"                  },
+  { "emc_grass.digging.up.xpos",                       "0"                             },
+  { "emc_grass.digging.up.ypos",                       "0"                             },
+  { "emc_grass.digging.up.frames",                     "3"                             },
+  { "emc_grass.digging.up.delay",                      "2"                             },
+  { "emc_grass.digging.up.anim_mode",                  "linear"                        },
+  { "emc_grass.digging.down",                          "RocksEMC.png"                  },
+  { "emc_grass.digging.down.xpos",                     "3"                             },
+  { "emc_grass.digging.down.ypos",                     "0"                             },
+  { "emc_grass.digging.down.frames",                   "3"                             },
+  { "emc_grass.digging.down.delay",                    "2"                             },
+  { "emc_grass.digging.down.anim_mode",                        "linear"                        },
+  { "emc_grass.digging.left.CRUMBLED",                 "RocksEMC.png"                  },
+  { "emc_grass.digging.left.CRUMBLED.xpos",            "6"                             },
+  { "emc_grass.digging.left.CRUMBLED.ypos",            "1"                             },
+  { "emc_grass.digging.left.CRUMBLED.frames",          "3"                             },
+  { "emc_grass.digging.left.CRUMBLED.delay",           "2"                             },
+  { "emc_grass.digging.left.CRUMBLED.anim_mode",       "linear"                        },
+  { "emc_grass.digging.right.CRUMBLED",                        "RocksEMC.png"                  },
+  { "emc_grass.digging.right.CRUMBLED.xpos",           "9"                             },
+  { "emc_grass.digging.right.CRUMBLED.ypos",           "1"                             },
+  { "emc_grass.digging.right.CRUMBLED.frames",         "3"                             },
+  { "emc_grass.digging.right.CRUMBLED.delay",          "2"                             },
+  { "emc_grass.digging.right.CRUMBLED.anim_mode",      "linear"                        },
+  { "emc_grass.digging.up.CRUMBLED",                   "RocksEMC.png"                  },
+  { "emc_grass.digging.up.CRUMBLED.xpos",              "0"                             },
+  { "emc_grass.digging.up.CRUMBLED.ypos",              "1"                             },
+  { "emc_grass.digging.up.CRUMBLED.frames",            "3"                             },
+  { "emc_grass.digging.up.CRUMBLED.delay",             "2"                             },
+  { "emc_grass.digging.up.CRUMBLED.anim_mode",         "linear"                        },
+  { "emc_grass.digging.down.CRUMBLED",                 "RocksEMC.png"                  },
+  { "emc_grass.digging.down.CRUMBLED.xpos",            "3"                             },
+  { "emc_grass.digging.down.CRUMBLED.ypos",            "1"                             },
+  { "emc_grass.digging.down.CRUMBLED.frames",          "3"                             },
+  { "emc_grass.digging.down.CRUMBLED.delay",           "2"                             },
+  { "emc_grass.digging.down.CRUMBLED.anim_mode",       "linear"                        },
+
+  { "emc_magic_ball",                                  "RocksEMC.png"                  },
+  { "emc_magic_ball.xpos",                             "0"                             },
+  { "emc_magic_ball.ypos",                             "9"                             },
+  { "emc_magic_ball.frames",                           "1"                             },
+  { "emc_magic_ball.active",                           "RocksEMC.png"                  },
+  { "emc_magic_ball.active.xpos",                      "0"                             },
+  { "emc_magic_ball.active.ypos",                      "9"                             },
+  { "emc_magic_ball.active.frames",                    "16"                            },
+  { "emc_magic_ball.active.frames_per_line",           "8"                             },
+  { "emc_magic_ball.dropping",                         "RocksElements.png"             },
+  { "emc_magic_ball.dropping.xpos",                    "0"                             },
+  { "emc_magic_ball.dropping.ypos",                    "4"                             },
+  { "emc_magic_ball.dropping.frames",                  "8"                             },
+  { "emc_magic_ball.dropping.anim_mode",               "linear"                        },
+
+  { "emc_magic_ball_switch",                           "RocksEMC.png"                  },
+  { "emc_magic_ball_switch.xpos",                      "8"                             },
+  { "emc_magic_ball_switch.ypos",                      "10"                            },
+  { "emc_magic_ball_switch.frames",                    "1"                             },
+  { "emc_magic_ball_switch.active",                    "RocksEMC.png"                  },
+  { "emc_magic_ball_switch.active.xpos",               "8"                             },
+  { "emc_magic_ball_switch.active.ypos",               "9"                             },
+  { "emc_magic_ball_switch.active.frames",             "1"                             },
+
+  { "emc_spring_bumper",                               "RocksEMC.png"                  },
+  { "emc_spring_bumper.xpos",                          "8"                             },
+  { "emc_spring_bumper.ypos",                          "4"                             },
+  { "emc_spring_bumper.frames",                                "1"                             },
+
+  { "emc_spring_bumper.active",                                "RocksEMC.png"                  },
+  { "emc_spring_bumper.active.xpos",                   "8"                             },
+  { "emc_spring_bumper.active.ypos",                   "4"                             },
+  { "emc_spring_bumper.active.frames",                 "4"                             },
+  { "emc_spring_bumper.active.anim_mode",              "pingpong2"                     },
+
+  { "emc_plant",                                       "RocksEMC.png"                  },
+  { "emc_plant.xpos",                                  "4"                             },
+  { "emc_plant.ypos",                                  "4"                             },
+  { "emc_plant.frames",                                        "1"                             },
+  { "emc_plant.CRUMBLED",                              "RocksEMC.png"                  },
+  { "emc_plant.CRUMBLED.xpos",                         "5"                             },
+  { "emc_plant.CRUMBLED.ypos",                         "4"                             },
+  { "emc_plant.CRUMBLED.frames",                       "1"                             },
+
+  { "emc_lenses",                                      "RocksEMC.png"                  },
+  { "emc_lenses.xpos",                                 "6"                             },
+  { "emc_lenses.ypos",                                 "4"                             },
+  { "emc_lenses.frames",                               "1"                             },
+  { "emc_lenses.collecting",                           "RocksCollect.png"              },
+  { "emc_lenses.collecting.xpos",                      "7"                             },
+  { "emc_lenses.collecting.ypos",                      "16"                            },
+  { "emc_lenses.collecting.frames",                    "7"                             },
+  { "emc_lenses.collecting.anim_mode",                 "linear"                        },
+
+  { "emc_magnifier",                                   "RocksEMC.png"                  },
+  { "emc_magnifier.xpos",                              "7"                             },
+  { "emc_magnifier.ypos",                              "4"                             },
+  { "emc_magnifier.frames",                            "1"                             },
+  { "emc_magnifier.collecting",                                "RocksCollect.png"              },
+  { "emc_magnifier.collecting.xpos",                   "7"                             },
+  { "emc_magnifier.collecting.ypos",                   "17"                            },
+  { "emc_magnifier.collecting.frames",                 "7"                             },
+  { "emc_magnifier.collecting.anim_mode",              "linear"                        },
+
+  { "emc_wall_9",                                      "RocksEMC.png"                  },
+  { "emc_wall_9.xpos",                                 "10"                            },
+  { "emc_wall_9.ypos",                                 "5"                             },
+  { "emc_wall_9.frames",                               "1"                             },
+  { "emc_wall_10",                                     "RocksEMC.png"                  },
+  { "emc_wall_10.xpos",                                        "10"                            },
+  { "emc_wall_10.ypos",                                        "6"                             },
+  { "emc_wall_10.frames",                              "1"                             },
+  { "emc_wall_11",                                     "RocksEMC.png"                  },
+  { "emc_wall_11.xpos",                                        "11"                            },
+  { "emc_wall_11.ypos",                                        "5"                             },
+  { "emc_wall_11.frames",                              "1"                             },
+  { "emc_wall_12",                                     "RocksEMC.png"                  },
+  { "emc_wall_12.xpos",                                        "11"                            },
+  { "emc_wall_12.ypos",                                        "6"                             },
+  { "emc_wall_12.frames",                              "1"                             },
+  { "emc_wall_13",                                     "RocksEMC.png"                  },
+  { "emc_wall_13.xpos",                                        "10"                            },
+  { "emc_wall_13.ypos",                                        "7"                             },
+  { "emc_wall_13.frames",                              "1"                             },
+  { "emc_wall_14",                                     "RocksEMC.png"                  },
+  { "emc_wall_14.xpos",                                        "10"                            },
+  { "emc_wall_14.ypos",                                        "8"                             },
+  { "emc_wall_14.frames",                              "1"                             },
+  { "emc_wall_15",                                     "RocksEMC.png"                  },
+  { "emc_wall_15.xpos",                                        "10"                            },
+  { "emc_wall_15.ypos",                                        "9"                             },
+  { "emc_wall_15.frames",                              "1"                             },
+  { "emc_wall_16",                                     "RocksEMC.png"                  },
+  { "emc_wall_16.xpos",                                        "10"                            },
+  { "emc_wall_16.ypos",                                        "10"                            },
+  { "emc_wall_16.frames",                              "1"                             },
+
+  { "emc_wall_slippery_1",                             "RocksEMC.png"                  },
+  { "emc_wall_slippery_1.xpos",                                "11"                            },
+  { "emc_wall_slippery_1.ypos",                                "7"                             },
+  { "emc_wall_slippery_1.frames",                      "1"                             },
+  { "emc_wall_slippery_2",                             "RocksEMC.png"                  },
+  { "emc_wall_slippery_2.xpos",                                "11"                            },
+  { "emc_wall_slippery_2.ypos",                                "8"                             },
+  { "emc_wall_slippery_2.frames",                      "1"                             },
+  { "emc_wall_slippery_3",                             "RocksEMC.png"                  },
+  { "emc_wall_slippery_3.xpos",                                "11"                            },
+  { "emc_wall_slippery_3.ypos",                                "9"                             },
+  { "emc_wall_slippery_3.frames",                      "1"                             },
+  { "emc_wall_slippery_4",                             "RocksEMC.png"                  },
+  { "emc_wall_slippery_4.xpos",                                "11"                            },
+  { "emc_wall_slippery_4.ypos",                                "10"                            },
+  { "emc_wall_slippery_4.frames",                      "1"                             },
+
+  { "emc_fake_grass",                                  "RocksEMC.png"                  },
+  { "emc_fake_grass.xpos",                             "0"                             },
+  { "emc_fake_grass.ypos",                             "4"                             },
+  { "emc_fake_grass.frames",                           "1"                             },
+  { "emc_fake_grass.CRUMBLED",                         "RocksEMC.png"                  },
+  { "emc_fake_grass.CRUMBLED.xpos",                    "1"                             },
+  { "emc_fake_grass.CRUMBLED.ypos",                    "4"                             },
+  { "emc_fake_grass.CRUMBLED.frames",                  "1"                             },
+  { "emc_fake_grass.active",                           "RocksEMC.png"                  },
+  { "emc_fake_grass.active.xpos",                      "2"                             },
+  { "emc_fake_grass.active.ypos",                      "4"                             },
+  { "emc_fake_grass.active.frames",                    "1"                             },
+  { "emc_fake_grass.active.CRUMBLED",                  "RocksEMC.png"                  },
+  { "emc_fake_grass.active.CRUMBLED.xpos",             "3"                             },
+  { "emc_fake_grass.active.CRUMBLED.ypos",             "4"                             },
+  { "emc_fake_grass.active.CRUMBLED.frames",           "1"                             },
+  { "emc_fake_grass.EDITOR",                           "RocksEMC.png"                  },
+  { "emc_fake_grass.EDITOR.xpos",                      "2"                             },
+  { "emc_fake_grass.EDITOR.ypos",                      "4"                             },
+  { "emc_fake_grass.EDITOR.frames",                    "1"                             },
+
+  { "emc_fake_acid",                                   "RocksElements.png"             },
+  { "emc_fake_acid.xpos",                              "12"                            },
+  { "emc_fake_acid.ypos",                              "7"                             },
+  { "emc_fake_acid.frames",                            "4"                             },
+  { "emc_fake_acid.delay",                             "10"                            },
+  { "emc_fake_acid.global_sync",                       "true"                          },
+
+  { "emc_dripper",                                     "RocksSP.png"                   },
+  { "emc_dripper.xpos",                                        "0"                             },
+  { "emc_dripper.ypos",                                        "0"                             },
+  { "emc_dripper.frames",                              "1"                             },
+  { "emc_dripper.EDITOR",                              "RocksEMC.png"                  },
+  { "emc_dripper.EDITOR.xpos",                         "8"                             },
+  { "emc_dripper.EDITOR.ypos",                         "8"                             },
+  { "emc_dripper.active",                              "RocksEMC.png"                  },
+  { "emc_dripper.active.xpos",                         "8"                             },
+  { "emc_dripper.active.ypos",                         "8"                             },
+  { "emc_dripper.active.frames",                       "1"                             },
+
+  { "mm_mcduffin",                                     "RocksMM.png"                   },
+  { "mm_mcduffin.xpos",                                        "4"                             },
+  { "mm_mcduffin.ypos",                                        "1"                             },
+  { "mm_mcduffin.frames",                              "4"                             },
+  { "mm_mcduffin.delay",                               "8"                             },
+  { "mm_mcduffin.right",                               "RocksMM.png"                   },
+  { "mm_mcduffin.right.xpos",                          "4"                             },
+  { "mm_mcduffin.right.ypos",                          "1"                             },
+  { "mm_mcduffin.right.frames",                                "1"                             },
+  { "mm_mcduffin.up",                                  "RocksMM.png"                   },
+  { "mm_mcduffin.up.xpos",                             "5"                             },
+  { "mm_mcduffin.up.ypos",                             "1"                             },
+  { "mm_mcduffin.up.frames",                           "1"                             },
+  { "mm_mcduffin.left",                                        "RocksMM.png"                   },
+  { "mm_mcduffin.left.xpos",                           "6"                             },
+  { "mm_mcduffin.left.ypos",                           "1"                             },
+  { "mm_mcduffin.left.frames",                         "1"                             },
+  { "mm_mcduffin.down",                                        "RocksMM.png"                   },
+  { "mm_mcduffin.down.xpos",                           "7"                             },
+  { "mm_mcduffin.down.ypos",                           "1"                             },
+  { "mm_mcduffin.down.frames",                         "1"                             },
+
+  { "mm_exit_closed",                                  "RocksMM.png"                   },
+  { "mm_exit_closed.xpos",                             "8"                             },
+  { "mm_exit_closed.ypos",                             "1"                             },
+  { "mm_exit_closed.frames",                           "1"                             },
+  { "mm_exit.opening",                                 "RocksMM.png"                   },
+  { "mm_exit.opening.xpos",                            "8"                             },
+  { "mm_exit.opening.ypos",                            "1"                             },
+  { "mm_exit.opening.frames",                          "4"                             },
+  { "mm_exit.opening.delay",                           "6"                             },
+  { "mm_exit.opening.anim_mode",                       "linear"                        },
+  { "mm_exit_open",                                    "RocksMM.png"                   },
+  { "mm_exit_open.xpos",                               "11"                            },
+  { "mm_exit_open.ypos",                               "1"                             },
+  { "mm_exit_open.frames",                             "1"                             },
+  { "mm_exit.closing",                                 "RocksMM.png"                   },
+  { "mm_exit.closing.xpos",                            "8"                             },
+  { "mm_exit.closing.ypos",                            "1"                             },
+  { "mm_exit.closing.frames",                          "4"                             },
+  { "mm_exit.closing.delay",                           "6"                             },
+  { "mm_exit.closing.anim_mode",                       "linear,reverse"                },
+
+  { "mm_mirror_1",                                     "RocksMM.png"                   },
+  { "mm_mirror_1.xpos",                                        "0"                             },
+  { "mm_mirror_1.ypos",                                        "0"                             },
+  { "mm_mirror_1.frames",                              "1"                             },
+  { "mm_mirror_2",                                     "RocksMM.png"                   },
+  { "mm_mirror_2.xpos",                                        "1"                             },
+  { "mm_mirror_2.ypos",                                        "0"                             },
+  { "mm_mirror_2.frames",                              "1"                             },
+  { "mm_mirror_3",                                     "RocksMM.png"                   },
+  { "mm_mirror_3.xpos",                                        "2"                             },
+  { "mm_mirror_3.ypos",                                        "0"                             },
+  { "mm_mirror_3.frames",                              "1"                             },
+  { "mm_mirror_4",                                     "RocksMM.png"                   },
+  { "mm_mirror_4.xpos",                                        "3"                             },
+  { "mm_mirror_4.ypos",                                        "0"                             },
+  { "mm_mirror_4.frames",                              "1"                             },
+  { "mm_mirror_5",                                     "RocksMM.png"                   },
+  { "mm_mirror_5.xpos",                                        "4"                             },
+  { "mm_mirror_5.ypos",                                        "0"                             },
+  { "mm_mirror_5.frames",                              "1"                             },
+  { "mm_mirror_6",                                     "RocksMM.png"                   },
+  { "mm_mirror_6.xpos",                                        "5"                             },
+  { "mm_mirror_6.ypos",                                        "0"                             },
+  { "mm_mirror_6.frames",                              "1"                             },
+  { "mm_mirror_7",                                     "RocksMM.png"                   },
+  { "mm_mirror_7.xpos",                                        "6"                             },
+  { "mm_mirror_7.ypos",                                        "0"                             },
+  { "mm_mirror_7.frames",                              "1"                             },
+  { "mm_mirror_8",                                     "RocksMM.png"                   },
+  { "mm_mirror_8.xpos",                                        "7"                             },
+  { "mm_mirror_8.ypos",                                        "0"                             },
+  { "mm_mirror_8.frames",                              "1"                             },
+  { "mm_mirror_9",                                     "RocksMM.png"                   },
+  { "mm_mirror_9.xpos",                                        "8"                             },
+  { "mm_mirror_9.ypos",                                        "0"                             },
+  { "mm_mirror_9.frames",                              "1"                             },
+  { "mm_mirror_10",                                    "RocksMM.png"                   },
+  { "mm_mirror_10.xpos",                               "9"                             },
+  { "mm_mirror_10.ypos",                               "0"                             },
+  { "mm_mirror_10.frames",                             "1"                             },
+  { "mm_mirror_11",                                    "RocksMM.png"                   },
+  { "mm_mirror_11.xpos",                               "10"                            },
+  { "mm_mirror_11.ypos",                               "0"                             },
+  { "mm_mirror_11.frames",                             "1"                             },
+  { "mm_mirror_12",                                    "RocksMM.png"                   },
+  { "mm_mirror_12.xpos",                               "11"                            },
+  { "mm_mirror_12.ypos",                               "0"                             },
+  { "mm_mirror_12.frames",                             "1"                             },
+  { "mm_mirror_13",                                    "RocksMM.png"                   },
+  { "mm_mirror_13.xpos",                               "12"                            },
+  { "mm_mirror_13.ypos",                               "0"                             },
+  { "mm_mirror_13.frames",                             "1"                             },
+  { "mm_mirror_14",                                    "RocksMM.png"                   },
+  { "mm_mirror_14.xpos",                               "13"                            },
+  { "mm_mirror_14.ypos",                               "0"                             },
+  { "mm_mirror_14.frames",                             "1"                             },
+  { "mm_mirror_15",                                    "RocksMM.png"                   },
+  { "mm_mirror_15.xpos",                               "14"                            },
+  { "mm_mirror_15.ypos",                               "0"                             },
+  { "mm_mirror_15.frames",                             "1"                             },
+  { "mm_mirror_16",                                    "RocksMM.png"                   },
+  { "mm_mirror_16.xpos",                               "15"                            },
+  { "mm_mirror_16.ypos",                               "0"                             },
+  { "mm_mirror_16.frames",                             "1"                             },
+
+  { "mm_mirror_fixed_1",                               "RocksMM.png"                   },
+  { "mm_mirror_fixed_1.xpos",                          "4"                             },
+  { "mm_mirror_fixed_1.ypos",                          "6"                             },
+  { "mm_mirror_fixed_1.frames",                                "1"                             },
+  { "mm_mirror_fixed_2",                               "RocksMM.png"                   },
+  { "mm_mirror_fixed_2.xpos",                          "5"                             },
+  { "mm_mirror_fixed_2.ypos",                          "6"                             },
+  { "mm_mirror_fixed_2.frames",                                "1"                             },
+  { "mm_mirror_fixed_3",                               "RocksMM.png"                   },
+  { "mm_mirror_fixed_3.xpos",                          "6"                             },
+  { "mm_mirror_fixed_3.ypos",                          "6"                             },
+  { "mm_mirror_fixed_3.frames",                                "1"                             },
+  { "mm_mirror_fixed_4",                               "RocksMM.png"                   },
+  { "mm_mirror_fixed_4.xpos",                          "7"                             },
+  { "mm_mirror_fixed_4.ypos",                          "6"                             },
+  { "mm_mirror_fixed_4.frames",                                "1"                             },
+
+  { "mm_steel_grid_fixed_1",                           "RocksMM.png"                   },
+  { "mm_steel_grid_fixed_1.xpos",                      "0"                             },
+  { "mm_steel_grid_fixed_1.ypos",                      "1"                             },
+  { "mm_steel_grid_fixed_1.frames",                    "1"                             },
+  { "mm_steel_grid_fixed_2",                           "RocksMM.png"                   },
+  { "mm_steel_grid_fixed_2.xpos",                      "1"                             },
+  { "mm_steel_grid_fixed_2.ypos",                      "1"                             },
+  { "mm_steel_grid_fixed_2.frames",                    "1"                             },
+  { "mm_steel_grid_fixed_3",                           "RocksMM.png"                   },
+  { "mm_steel_grid_fixed_3.xpos",                      "2"                             },
+  { "mm_steel_grid_fixed_3.ypos",                      "1"                             },
+  { "mm_steel_grid_fixed_3.frames",                    "1"                             },
+  { "mm_steel_grid_fixed_4",                           "RocksMM.png"                   },
+  { "mm_steel_grid_fixed_4.xpos",                      "3"                             },
+  { "mm_steel_grid_fixed_4.ypos",                      "1"                             },
+  { "mm_steel_grid_fixed_4.frames",                    "1"                             },
+
+  { "mm_wooden_grid_fixed_1",                          "RocksMM.png"                   },
+  { "mm_wooden_grid_fixed_1.xpos",                     "12"                            },
+  { "mm_wooden_grid_fixed_1.ypos",                     "6"                             },
+  { "mm_wooden_grid_fixed_1.frames",                   "1"                             },
+  { "mm_wooden_grid_fixed_2",                          "RocksMM.png"                   },
+  { "mm_wooden_grid_fixed_2.xpos",                     "13"                            },
+  { "mm_wooden_grid_fixed_2.ypos",                     "6"                             },
+  { "mm_wooden_grid_fixed_2.frames",                   "1"                             },
+  { "mm_wooden_grid_fixed_3",                          "RocksMM.png"                   },
+  { "mm_wooden_grid_fixed_3.xpos",                     "14"                            },
+  { "mm_wooden_grid_fixed_3.ypos",                     "6"                             },
+  { "mm_wooden_grid_fixed_3.frames",                   "1"                             },
+  { "mm_wooden_grid_fixed_4",                          "RocksMM.png"                   },
+  { "mm_wooden_grid_fixed_4.xpos",                     "15"                            },
+  { "mm_wooden_grid_fixed_4.ypos",                     "6"                             },
+  { "mm_wooden_grid_fixed_4.frames",                   "1"                             },
+
+  { "mm_polarizer_1",                                  "RocksMM.png"                   },
+  { "mm_polarizer_1.xpos",                             "0"                             },
+  { "mm_polarizer_1.ypos",                             "5"                             },
+  { "mm_polarizer_1.frames",                           "1"                             },
+  { "mm_polarizer_2",                                  "RocksMM.png"                   },
+  { "mm_polarizer_2.xpos",                             "1"                             },
+  { "mm_polarizer_2.ypos",                             "5"                             },
+  { "mm_polarizer_2.frames",                           "1"                             },
+  { "mm_polarizer_3",                                  "RocksMM.png"                   },
+  { "mm_polarizer_3.xpos",                             "2"                             },
+  { "mm_polarizer_3.ypos",                             "5"                             },
+  { "mm_polarizer_3.frames",                           "1"                             },
+  { "mm_polarizer_4",                                  "RocksMM.png"                   },
+  { "mm_polarizer_4.xpos",                             "3"                             },
+  { "mm_polarizer_4.ypos",                             "5"                             },
+  { "mm_polarizer_4.frames",                           "1"                             },
+  { "mm_polarizer_5",                                  "RocksMM.png"                   },
+  { "mm_polarizer_5.xpos",                             "4"                             },
+  { "mm_polarizer_5.ypos",                             "5"                             },
+  { "mm_polarizer_5.frames",                           "1"                             },
+  { "mm_polarizer_6",                                  "RocksMM.png"                   },
+  { "mm_polarizer_6.xpos",                             "5"                             },
+  { "mm_polarizer_6.ypos",                             "5"                             },
+  { "mm_polarizer_6.frames",                           "1"                             },
+  { "mm_polarizer_7",                                  "RocksMM.png"                   },
+  { "mm_polarizer_7.xpos",                             "6"                             },
+  { "mm_polarizer_7.ypos",                             "5"                             },
+  { "mm_polarizer_7.frames",                           "1"                             },
+  { "mm_polarizer_8",                                  "RocksMM.png"                   },
+  { "mm_polarizer_8.xpos",                             "7"                             },
+  { "mm_polarizer_8.ypos",                             "5"                             },
+  { "mm_polarizer_8.frames",                           "1"                             },
+  { "mm_polarizer_9",                                  "RocksMM.png"                   },
+  { "mm_polarizer_9.xpos",                             "8"                             },
+  { "mm_polarizer_9.ypos",                             "5"                             },
+  { "mm_polarizer_9.frames",                           "1"                             },
+  { "mm_polarizer_10",                                 "RocksMM.png"                   },
+  { "mm_polarizer_10.xpos",                            "9"                             },
+  { "mm_polarizer_10.ypos",                            "5"                             },
+  { "mm_polarizer_10.frames",                          "1"                             },
+  { "mm_polarizer_11",                                 "RocksMM.png"                   },
+  { "mm_polarizer_11.xpos",                            "10"                            },
+  { "mm_polarizer_11.ypos",                            "5"                             },
+  { "mm_polarizer_11.frames",                          "1"                             },
+  { "mm_polarizer_12",                                 "RocksMM.png"                   },
+  { "mm_polarizer_12.xpos",                            "11"                            },
+  { "mm_polarizer_12.ypos",                            "5"                             },
+  { "mm_polarizer_12.frames",                          "1"                             },
+  { "mm_polarizer_13",                                 "RocksMM.png"                   },
+  { "mm_polarizer_13.xpos",                            "12"                            },
+  { "mm_polarizer_13.ypos",                            "5"                             },
+  { "mm_polarizer_13.frames",                          "1"                             },
+  { "mm_polarizer_14",                                 "RocksMM.png"                   },
+  { "mm_polarizer_14.xpos",                            "13"                            },
+  { "mm_polarizer_14.ypos",                            "5"                             },
+  { "mm_polarizer_14.frames",                          "1"                             },
+  { "mm_polarizer_15",                                 "RocksMM.png"                   },
+  { "mm_polarizer_15.xpos",                            "14"                            },
+  { "mm_polarizer_15.ypos",                            "5"                             },
+  { "mm_polarizer_15.frames",                          "1"                             },
+  { "mm_polarizer_16",                                 "RocksMM.png"                   },
+  { "mm_polarizer_16.xpos",                            "15"                            },
+  { "mm_polarizer_16.ypos",                            "5"                             },
+  { "mm_polarizer_16.frames",                          "1"                             },
+
+  { "mm_polarizer_cross_1",                            "RocksMM.png"                   },
+  { "mm_polarizer_cross_1.xpos",                       "0"                             },
+  { "mm_polarizer_cross_1.ypos",                       "6"                             },
+  { "mm_polarizer_cross_1.frames",                     "1"                             },
+  { "mm_polarizer_cross_2",                            "RocksMM.png"                   },
+  { "mm_polarizer_cross_2.xpos",                       "1"                             },
+  { "mm_polarizer_cross_2.ypos",                       "6"                             },
+  { "mm_polarizer_cross_2.frames",                     "1"                             },
+  { "mm_polarizer_cross_3",                            "RocksMM.png"                   },
+  { "mm_polarizer_cross_3.xpos",                       "2"                             },
+  { "mm_polarizer_cross_3.ypos",                       "6"                             },
+  { "mm_polarizer_cross_3.frames",                     "1"                             },
+  { "mm_polarizer_cross_4",                            "RocksMM.png"                   },
+  { "mm_polarizer_cross_4.xpos",                       "3"                             },
+  { "mm_polarizer_cross_4.ypos",                       "6"                             },
+  { "mm_polarizer_cross_4.frames",                     "1"                             },
+
+  { "mm_teleporter_1",                                 "RocksMM.png"                   },
+  { "mm_teleporter_1.xpos",                            "0"                             },
+  { "mm_teleporter_1.ypos",                            "3"                             },
+  { "mm_teleporter_1.frames",                          "1"                             },
+  { "mm_teleporter_2",                                 "RocksMM.png"                   },
+  { "mm_teleporter_2.xpos",                            "1"                             },
+  { "mm_teleporter_2.ypos",                            "3"                             },
+  { "mm_teleporter_2.frames",                          "1"                             },
+  { "mm_teleporter_3",                                 "RocksMM.png"                   },
+  { "mm_teleporter_3.xpos",                            "2"                             },
+  { "mm_teleporter_3.ypos",                            "3"                             },
+  { "mm_teleporter_3.frames",                          "1"                             },
+  { "mm_teleporter_4",                                 "RocksMM.png"                   },
+  { "mm_teleporter_4.xpos",                            "3"                             },
+  { "mm_teleporter_4.ypos",                            "3"                             },
+  { "mm_teleporter_4.frames",                          "1"                             },
+  { "mm_teleporter_5",                                 "RocksMM.png"                   },
+  { "mm_teleporter_5.xpos",                            "4"                             },
+  { "mm_teleporter_5.ypos",                            "3"                             },
+  { "mm_teleporter_5.frames",                          "1"                             },
+  { "mm_teleporter_6",                                 "RocksMM.png"                   },
+  { "mm_teleporter_6.xpos",                            "5"                             },
+  { "mm_teleporter_6.ypos",                            "3"                             },
+  { "mm_teleporter_6.frames",                          "1"                             },
+  { "mm_teleporter_7",                                 "RocksMM.png"                   },
+  { "mm_teleporter_7.xpos",                            "6"                             },
+  { "mm_teleporter_7.ypos",                            "3"                             },
+  { "mm_teleporter_7.frames",                          "1"                             },
+  { "mm_teleporter_8",                                 "RocksMM.png"                   },
+  { "mm_teleporter_8.xpos",                            "7"                             },
+  { "mm_teleporter_8.ypos",                            "3"                             },
+  { "mm_teleporter_8.frames",                          "1"                             },
+  { "mm_teleporter_9",                                 "RocksMM.png"                   },
+  { "mm_teleporter_9.xpos",                            "8"                             },
+  { "mm_teleporter_9.ypos",                            "3"                             },
+  { "mm_teleporter_9.frames",                          "1"                             },
+  { "mm_teleporter_10",                                        "RocksMM.png"                   },
+  { "mm_teleporter_10.xpos",                           "9"                             },
+  { "mm_teleporter_10.ypos",                           "3"                             },
+  { "mm_teleporter_10.frames",                         "1"                             },
+  { "mm_teleporter_11",                                        "RocksMM.png"                   },
+  { "mm_teleporter_11.xpos",                           "10"                            },
+  { "mm_teleporter_11.ypos",                           "3"                             },
+  { "mm_teleporter_11.frames",                         "1"                             },
+  { "mm_teleporter_12",                                        "RocksMM.png"                   },
+  { "mm_teleporter_12.xpos",                           "11"                            },
+  { "mm_teleporter_12.ypos",                           "3"                             },
+  { "mm_teleporter_12.frames",                         "1"                             },
+  { "mm_teleporter_13",                                        "RocksMM.png"                   },
+  { "mm_teleporter_13.xpos",                           "12"                            },
+  { "mm_teleporter_13.ypos",                           "3"                             },
+  { "mm_teleporter_13.frames",                         "1"                             },
+  { "mm_teleporter_14",                                        "RocksMM.png"                   },
+  { "mm_teleporter_14.xpos",                           "13"                            },
+  { "mm_teleporter_14.ypos",                           "3"                             },
+  { "mm_teleporter_14.frames",                         "1"                             },
+  { "mm_teleporter_15",                                        "RocksMM.png"                   },
+  { "mm_teleporter_15.xpos",                           "14"                            },
+  { "mm_teleporter_15.ypos",                           "3"                             },
+  { "mm_teleporter_15.frames",                         "1"                             },
+  { "mm_teleporter_16",                                        "RocksMM.png"                   },
+  { "mm_teleporter_16.xpos",                           "15"                            },
+  { "mm_teleporter_16.ypos",                           "3"                             },
+  { "mm_teleporter_16.frames",                         "1"                             },
+
+  { "mm_teleporter_red_1",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_1.xpos",                                "0"                             },
+  { "mm_teleporter_red_1.ypos",                                "4"                             },
+  { "mm_teleporter_red_1.frames",                      "1"                             },
+  { "mm_teleporter_red_2",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_2.xpos",                                "1"                             },
+  { "mm_teleporter_red_2.ypos",                                "4"                             },
+  { "mm_teleporter_red_2.frames",                      "1"                             },
+  { "mm_teleporter_red_3",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_3.xpos",                                "2"                             },
+  { "mm_teleporter_red_3.ypos",                                "4"                             },
+  { "mm_teleporter_red_3.frames",                      "1"                             },
+  { "mm_teleporter_red_4",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_4.xpos",                                "3"                             },
+  { "mm_teleporter_red_4.ypos",                                "4"                             },
+  { "mm_teleporter_red_4.frames",                      "1"                             },
+  { "mm_teleporter_red_5",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_5.xpos",                                "4"                             },
+  { "mm_teleporter_red_5.ypos",                                "4"                             },
+  { "mm_teleporter_red_5.frames",                      "1"                             },
+  { "mm_teleporter_red_6",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_6.xpos",                                "5"                             },
+  { "mm_teleporter_red_6.ypos",                                "4"                             },
+  { "mm_teleporter_red_6.frames",                      "1"                             },
+  { "mm_teleporter_red_7",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_7.xpos",                                "6"                             },
+  { "mm_teleporter_red_7.ypos",                                "4"                             },
+  { "mm_teleporter_red_7.frames",                      "1"                             },
+  { "mm_teleporter_red_8",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_8.xpos",                                "7"                             },
+  { "mm_teleporter_red_8.ypos",                                "4"                             },
+  { "mm_teleporter_red_8.frames",                      "1"                             },
+  { "mm_teleporter_red_9",                             "RocksDF.png"                   },
+  { "mm_teleporter_red_9.xpos",                                "8"                             },
+  { "mm_teleporter_red_9.ypos",                                "4"                             },
+  { "mm_teleporter_red_9.frames",                      "1"                             },
+  { "mm_teleporter_red_10",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_10.xpos",                       "9"                             },
+  { "mm_teleporter_red_10.ypos",                       "4"                             },
+  { "mm_teleporter_red_10.frames",                     "1"                             },
+  { "mm_teleporter_red_11",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_11.xpos",                       "10"                            },
+  { "mm_teleporter_red_11.ypos",                       "4"                             },
+  { "mm_teleporter_red_11.frames",                     "1"                             },
+  { "mm_teleporter_red_12",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_12.xpos",                       "11"                            },
+  { "mm_teleporter_red_12.ypos",                       "4"                             },
+  { "mm_teleporter_red_12.frames",                     "1"                             },
+  { "mm_teleporter_red_13",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_13.xpos",                       "12"                            },
+  { "mm_teleporter_red_13.ypos",                       "4"                             },
+  { "mm_teleporter_red_13.frames",                     "1"                             },
+  { "mm_teleporter_red_14",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_14.xpos",                       "13"                            },
+  { "mm_teleporter_red_14.ypos",                       "4"                             },
+  { "mm_teleporter_red_14.frames",                     "1"                             },
+  { "mm_teleporter_red_15",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_15.xpos",                       "14"                            },
+  { "mm_teleporter_red_15.ypos",                       "4"                             },
+  { "mm_teleporter_red_15.frames",                     "1"                             },
+  { "mm_teleporter_red_16",                            "RocksDF.png"                   },
+  { "mm_teleporter_red_16.xpos",                       "15"                            },
+  { "mm_teleporter_red_16.ypos",                       "4"                             },
+  { "mm_teleporter_red_16.frames",                     "1"                             },
+
+  { "mm_teleporter_yellow_1",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_1.xpos",                     "0"                             },
+  { "mm_teleporter_yellow_1.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_1.frames",                   "1"                             },
+  { "mm_teleporter_yellow_2",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_2.xpos",                     "1"                             },
+  { "mm_teleporter_yellow_2.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_2.frames",                   "1"                             },
+  { "mm_teleporter_yellow_3",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_3.xpos",                     "2"                             },
+  { "mm_teleporter_yellow_3.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_3.frames",                   "1"                             },
+  { "mm_teleporter_yellow_4",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_4.xpos",                     "3"                             },
+  { "mm_teleporter_yellow_4.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_4.frames",                   "1"                             },
+  { "mm_teleporter_yellow_5",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_5.xpos",                     "4"                             },
+  { "mm_teleporter_yellow_5.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_5.frames",                   "1"                             },
+  { "mm_teleporter_yellow_6",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_6.xpos",                     "5"                             },
+  { "mm_teleporter_yellow_6.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_6.frames",                   "1"                             },
+  { "mm_teleporter_yellow_7",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_7.xpos",                     "6"                             },
+  { "mm_teleporter_yellow_7.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_7.frames",                   "1"                             },
+  { "mm_teleporter_yellow_8",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_8.xpos",                     "7"                             },
+  { "mm_teleporter_yellow_8.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_8.frames",                   "1"                             },
+  { "mm_teleporter_yellow_9",                          "RocksDF.png"                   },
+  { "mm_teleporter_yellow_9.xpos",                     "8"                             },
+  { "mm_teleporter_yellow_9.ypos",                     "5"                             },
+  { "mm_teleporter_yellow_9.frames",                   "1"                             },
+  { "mm_teleporter_yellow_10",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_10.xpos",                    "9"                             },
+  { "mm_teleporter_yellow_10.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_10.frames",                  "1"                             },
+  { "mm_teleporter_yellow_11",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_11.xpos",                    "10"                            },
+  { "mm_teleporter_yellow_11.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_11.frames",                  "1"                             },
+  { "mm_teleporter_yellow_12",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_12.xpos",                    "11"                            },
+  { "mm_teleporter_yellow_12.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_12.frames",                  "1"                             },
+  { "mm_teleporter_yellow_13",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_13.xpos",                    "12"                            },
+  { "mm_teleporter_yellow_13.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_13.frames",                  "1"                             },
+  { "mm_teleporter_yellow_14",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_14.xpos",                    "13"                            },
+  { "mm_teleporter_yellow_14.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_14.frames",                  "1"                             },
+  { "mm_teleporter_yellow_15",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_15.xpos",                    "14"                            },
+  { "mm_teleporter_yellow_15.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_15.frames",                  "1"                             },
+  { "mm_teleporter_yellow_16",                         "RocksDF.png"                   },
+  { "mm_teleporter_yellow_16.xpos",                    "15"                            },
+  { "mm_teleporter_yellow_16.ypos",                    "5"                             },
+  { "mm_teleporter_yellow_16.frames",                  "1"                             },
+
+  { "mm_teleporter_green_1",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_1.xpos",                      "0"                             },
+  { "mm_teleporter_green_1.ypos",                      "6"                             },
+  { "mm_teleporter_green_1.frames",                    "1"                             },
+  { "mm_teleporter_green_2",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_2.xpos",                      "1"                             },
+  { "mm_teleporter_green_2.ypos",                      "6"                             },
+  { "mm_teleporter_green_2.frames",                    "1"                             },
+  { "mm_teleporter_green_3",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_3.xpos",                      "2"                             },
+  { "mm_teleporter_green_3.ypos",                      "6"                             },
+  { "mm_teleporter_green_3.frames",                    "1"                             },
+  { "mm_teleporter_green_4",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_4.xpos",                      "3"                             },
+  { "mm_teleporter_green_4.ypos",                      "6"                             },
+  { "mm_teleporter_green_4.frames",                    "1"                             },
+  { "mm_teleporter_green_5",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_5.xpos",                      "4"                             },
+  { "mm_teleporter_green_5.ypos",                      "6"                             },
+  { "mm_teleporter_green_5.frames",                    "1"                             },
+  { "mm_teleporter_green_6",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_6.xpos",                      "5"                             },
+  { "mm_teleporter_green_6.ypos",                      "6"                             },
+  { "mm_teleporter_green_6.frames",                    "1"                             },
+  { "mm_teleporter_green_7",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_7.xpos",                      "6"                             },
+  { "mm_teleporter_green_7.ypos",                      "6"                             },
+  { "mm_teleporter_green_7.frames",                    "1"                             },
+  { "mm_teleporter_green_8",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_8.xpos",                      "7"                             },
+  { "mm_teleporter_green_8.ypos",                      "6"                             },
+  { "mm_teleporter_green_8.frames",                    "1"                             },
+  { "mm_teleporter_green_9",                           "RocksDF.png"                   },
+  { "mm_teleporter_green_9.xpos",                      "8"                             },
+  { "mm_teleporter_green_9.ypos",                      "6"                             },
+  { "mm_teleporter_green_9.frames",                    "1"                             },
+  { "mm_teleporter_green_10",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_10.xpos",                     "9"                             },
+  { "mm_teleporter_green_10.ypos",                     "6"                             },
+  { "mm_teleporter_green_10.frames",                   "1"                             },
+  { "mm_teleporter_green_11",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_11.xpos",                     "10"                            },
+  { "mm_teleporter_green_11.ypos",                     "6"                             },
+  { "mm_teleporter_green_11.frames",                   "1"                             },
+  { "mm_teleporter_green_12",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_12.xpos",                     "11"                            },
+  { "mm_teleporter_green_12.ypos",                     "6"                             },
+  { "mm_teleporter_green_12.frames",                   "1"                             },
+  { "mm_teleporter_green_13",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_13.xpos",                     "12"                            },
+  { "mm_teleporter_green_13.ypos",                     "6"                             },
+  { "mm_teleporter_green_13.frames",                   "1"                             },
+  { "mm_teleporter_green_14",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_14.xpos",                     "13"                            },
+  { "mm_teleporter_green_14.ypos",                     "6"                             },
+  { "mm_teleporter_green_14.frames",                   "1"                             },
+  { "mm_teleporter_green_15",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_15.xpos",                     "14"                            },
+  { "mm_teleporter_green_15.ypos",                     "6"                             },
+  { "mm_teleporter_green_15.frames",                   "1"                             },
+  { "mm_teleporter_green_16",                          "RocksDF.png"                   },
+  { "mm_teleporter_green_16.xpos",                     "15"                            },
+  { "mm_teleporter_green_16.ypos",                     "6"                             },
+  { "mm_teleporter_green_16.frames",                   "1"                             },
+
+  { "mm_teleporter_blue_1",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_1.xpos",                       "0"                             },
+  { "mm_teleporter_blue_1.ypos",                       "7"                             },
+  { "mm_teleporter_blue_1.frames",                     "1"                             },
+  { "mm_teleporter_blue_2",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_2.xpos",                       "1"                             },
+  { "mm_teleporter_blue_2.ypos",                       "7"                             },
+  { "mm_teleporter_blue_2.frames",                     "1"                             },
+  { "mm_teleporter_blue_3",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_3.xpos",                       "2"                             },
+  { "mm_teleporter_blue_3.ypos",                       "7"                             },
+  { "mm_teleporter_blue_3.frames",                     "1"                             },
+  { "mm_teleporter_blue_4",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_4.xpos",                       "3"                             },
+  { "mm_teleporter_blue_4.ypos",                       "7"                             },
+  { "mm_teleporter_blue_4.frames",                     "1"                             },
+  { "mm_teleporter_blue_5",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_5.xpos",                       "4"                             },
+  { "mm_teleporter_blue_5.ypos",                       "7"                             },
+  { "mm_teleporter_blue_5.frames",                     "1"                             },
+  { "mm_teleporter_blue_6",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_6.xpos",                       "5"                             },
+  { "mm_teleporter_blue_6.ypos",                       "7"                             },
+  { "mm_teleporter_blue_6.frames",                     "1"                             },
+  { "mm_teleporter_blue_7",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_7.xpos",                       "6"                             },
+  { "mm_teleporter_blue_7.ypos",                       "7"                             },
+  { "mm_teleporter_blue_7.frames",                     "1"                             },
+  { "mm_teleporter_blue_8",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_8.xpos",                       "7"                             },
+  { "mm_teleporter_blue_8.ypos",                       "7"                             },
+  { "mm_teleporter_blue_8.frames",                     "1"                             },
+  { "mm_teleporter_blue_9",                            "RocksDF.png"                   },
+  { "mm_teleporter_blue_9.xpos",                       "8"                             },
+  { "mm_teleporter_blue_9.ypos",                       "7"                             },
+  { "mm_teleporter_blue_9.frames",                     "1"                             },
+  { "mm_teleporter_blue_10",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_10.xpos",                      "9"                             },
+  { "mm_teleporter_blue_10.ypos",                      "7"                             },
+  { "mm_teleporter_blue_10.frames",                    "1"                             },
+  { "mm_teleporter_blue_11",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_11.xpos",                      "10"                            },
+  { "mm_teleporter_blue_11.ypos",                      "7"                             },
+  { "mm_teleporter_blue_11.frames",                    "1"                             },
+  { "mm_teleporter_blue_12",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_12.xpos",                      "11"                            },
+  { "mm_teleporter_blue_12.ypos",                      "7"                             },
+  { "mm_teleporter_blue_12.frames",                    "1"                             },
+  { "mm_teleporter_blue_13",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_13.xpos",                      "12"                            },
+  { "mm_teleporter_blue_13.ypos",                      "7"                             },
+  { "mm_teleporter_blue_13.frames",                    "1"                             },
+  { "mm_teleporter_blue_14",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_14.xpos",                      "13"                            },
+  { "mm_teleporter_blue_14.ypos",                      "7"                             },
+  { "mm_teleporter_blue_14.frames",                    "1"                             },
+  { "mm_teleporter_blue_15",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_15.xpos",                      "14"                            },
+  { "mm_teleporter_blue_15.ypos",                      "7"                             },
+  { "mm_teleporter_blue_15.frames",                    "1"                             },
+  { "mm_teleporter_blue_16",                           "RocksDF.png"                   },
+  { "mm_teleporter_blue_16.xpos",                      "15"                            },
+  { "mm_teleporter_blue_16.ypos",                      "7"                             },
+  { "mm_teleporter_blue_16.frames",                    "1"                             },
+
+  { "mm_kettle",                                       "RocksMM.png"                   },
+  { "mm_kettle.xpos",                                  "9"                             },
+  { "mm_kettle.ypos",                                  "8"                             },
+  { "mm_kettle.frames",                                        "1"                             },
+  { "mm_kettle.exploding",                             "RocksMM.png"                   },
+  { "mm_kettle.exploding.xpos",                                "10"                            },
+  { "mm_kettle.exploding.ypos",                                "8"                             },
+  { "mm_kettle.exploding.frames",                      "6"                             },
+  { "mm_kettle.exploding.delay",                       "2"                             },
+  { "mm_kettle.exploding.anim_mode",                   "linear"                        },
+
+  { "mm_bomb",                                         "RocksMM.png"                   },
+  { "mm_bomb.xpos",                                    "5"                             },
+  { "mm_bomb.ypos",                                    "2"                             },
+  { "mm_bomb.frames",                                  "1"                             },
+  { "mm_bomb.active",                                  "RocksMM.png"                   },
+  { "mm_bomb.active.xpos",                             "12"                            },
+  { "mm_bomb.active.ypos",                             "1"                             },
+  { "mm_bomb.active.frames",                           "3"                             },
+  { "mm_bomb.active.delay",                            "6"                             },
+  { "mm_bomb.active.anim_mode",                                "pingpong"                      },
+
+  { "mm_prism",                                                "RocksMM.png"                   },
+  { "mm_prism.xpos",                                   "0"                             },
+  { "mm_prism.ypos",                                   "2"                             },
+  { "mm_prism.frames",                                 "1"                             },
+
+  { "mm_fuse",                                         "RocksMM.png"                   },
+  { "mm_fuse.xpos",                                    "7"                             },
+  { "mm_fuse.ypos",                                    "2"                             },
+  { "mm_fuse.frames",                                  "1"                             },
+  { "mm_fuse.active",                                  "RocksMM.png"                   },
+  { "mm_fuse.active.xpos",                             "6"                             },
+  { "mm_fuse.active.ypos",                             "2"                             },
+  { "mm_fuse.active.frames",                           "1"                             },
+
+  { "mm_steel_lock",                                   "RocksMM.png"                   },
+  { "mm_steel_lock.xpos",                              "8"                             },
+  { "mm_steel_lock.ypos",                              "2"                             },
+  { "mm_steel_lock.frames",                            "1"                             },
+  { "mm_steel_lock.exploding",                         "RocksMM.png"                   },
+  { "mm_steel_lock.exploding.xpos",                    "4"                             },
+  { "mm_steel_lock.exploding.ypos",                    "8"                             },
+  { "mm_steel_lock.exploding.frames",                  "5"                             },
+  { "mm_steel_lock.exploding.delay",                   "2"                             },
+  { "mm_steel_lock.exploding.anim_mode",               "linear"                        },
+
+  { "mm_wooden_lock",                                  "RocksMM.png"                   },
+  { "mm_wooden_lock.xpos",                             "9"                             },
+  { "mm_wooden_lock.ypos",                             "6"                             },
+  { "mm_wooden_lock.frames",                           "1"                             },
+  { "mm_wooden_lock.exploding",                                "RocksMM.png"                   },
+  { "mm_wooden_lock.exploding.xpos",                   "4"                             },
+  { "mm_wooden_lock.exploding.ypos",                   "8"                             },
+  { "mm_wooden_lock.exploding.frames",                 "5"                             },
+  { "mm_wooden_lock.exploding.delay",                  "2"                             },
+  { "mm_wooden_lock.exploding.anim_mode",              "linear"                        },
+
+  { "mm_steel_block",                                  "RocksMM.png"                   },
+  { "mm_steel_block.xpos",                             "8"                             },
+  { "mm_steel_block.ypos",                             "6"                             },
+  { "mm_steel_block.frames",                           "1"                             },
+
+  { "mm_wooden_block",                                 "RocksMM.png"                   },
+  { "mm_wooden_block.xpos",                            "4"                             },
+  { "mm_wooden_block.ypos",                            "2"                             },
+  { "mm_wooden_block.frames",                          "1"                             },
+
+  { "mm_key",                                          "RocksMM.png"                   },
+  { "mm_key.xpos",                                     "9"                             },
+  { "mm_key.ypos",                                     "2"                             },
+  { "mm_key.frames",                                   "1"                             },
+
+  { "mm_lightbulb",                                    "RocksMM.png"                   },
+  { "mm_lightbulb.xpos",                               "10"                            },
+  { "mm_lightbulb.ypos",                               "2"                             },
+  { "mm_lightbulb.frames",                             "1"                             },
+  { "mm_lightbulb.active",                             "RocksMM.png"                   },
+  { "mm_lightbulb.active.xpos",                                "11"                            },
+  { "mm_lightbulb.active.ypos",                                "2"                             },
+  { "mm_lightbulb.active.frames",                      "1"                             },
+
+  { "mm_lightball",                                    "RocksMM.png"                   },
+  { "mm_lightball.xpos",                               "12"                            },
+  { "mm_lightball.ypos",                               "2"                             },
+  { "mm_lightball.frames",                             "3"                             },
+  { "mm_lightball.anim_mode",                          "random_static"                 },
+  { "mm_lightball_red",                                        "RocksMM.png"                   },
+  { "mm_lightball_red.xpos",                           "12"                            },
+  { "mm_lightball_red.ypos",                           "2"                             },
+  { "mm_lightball_red.frames",                         "1"                             },
+  { "mm_lightball_blue",                               "RocksMM.png"                   },
+  { "mm_lightball_blue.xpos",                          "13"                            },
+  { "mm_lightball_blue.ypos",                          "2"                             },
+  { "mm_lightball_blue.frames",                                "1"                             },
+  { "mm_lightball_yellow",                             "RocksMM.png"                   },
+  { "mm_lightball_yellow.xpos",                                "14"                            },
+  { "mm_lightball_yellow.ypos",                                "2"                             },
+  { "mm_lightball_yellow.frames",                      "1"                             },
+
+  { "mm_gray_ball",                                    "RocksMM.png"                   },
+  { "mm_gray_ball.xpos",                               "15"                            },
+  { "mm_gray_ball.ypos",                               "2"                             },
+  { "mm_gray_ball.frames",                             "1"                             },
+  { "mm_gray_ball.active",                             "RocksMM.png"                   },
+  { "mm_gray_ball.active.xpos",                                "15"                            },
+  { "mm_gray_ball.active.ypos",                                "1"                             },
+  { "mm_gray_ball.active.frames",                      "2"                             },
+  { "mm_gray_ball.active.delay",                       "20"                            },
+  { "mm_gray_ball.active.vertical",                    "true"                          },
+  { "mm_gray_ball.EDITOR",                             "RocksMM.png"                   },
+  { "mm_gray_ball.EDITOR.xpos",                                "15"                            },
+  { "mm_gray_ball.EDITOR.ypos",                                "1"                             },
+  { "mm_gray_ball.EDITOR.frames",                      "1"                             },
+
+  { "mm_fuel_full",                                    "RocksMM.png"                   },
+  { "mm_fuel_full.xpos",                               "10"                            },
+  { "mm_fuel_full.ypos",                               "6"                             },
+  { "mm_fuel_full.frames",                             "1"                             },
+  { "mm_fuel_empty",                                   "RocksMM.png"                   },
+  { "mm_fuel_empty.xpos",                              "11"                            },
+  { "mm_fuel_empty.ypos",                              "6"                             },
+  { "mm_fuel_empty.frames",                            "1"                             },
+
+  { "mm_steel_wall",                                   "RocksMM.png"                   },
+  { "mm_steel_wall.xpos",                              "0"                             },
+  { "mm_steel_wall.ypos",                              "7"                             },
+  { "mm_steel_wall.frames",                            "1"                             },
+
+  { "mm_wooden_wall",                                  "RocksMM.png"                   },
+  { "mm_wooden_wall.xpos",                             "1"                             },
+  { "mm_wooden_wall.ypos",                             "7"                             },
+  { "mm_wooden_wall.frames",                           "1"                             },
+
+  { "mm_ice_wall",                                     "RocksMM.png"                   },
+  { "mm_ice_wall.xpos",                                        "2"                             },
+  { "mm_ice_wall.ypos",                                        "7"                             },
+  { "mm_ice_wall.frames",                              "1"                             },
+  { "mm_ice_wall.shrinking",                           "RocksMM.png"                   },
+  { "mm_ice_wall.shrinking.xpos",                      "2"                             },
+  { "mm_ice_wall.shrinking.ypos",                      "7"                             },
+  { "mm_ice_wall.shrinking.frames",                    "5"                             },
+  { "mm_ice_wall.shrinking.delay",                     "8"                             },
+  { "mm_ice_wall.shrinking.anim_mode",                 "linear"                        },
+
+  { "mm_amoeba_wall",                                  "RocksMM.png"                   },
+  { "mm_amoeba_wall.xpos",                             "8"                             },
+  { "mm_amoeba_wall.ypos",                             "7"                             },
+  { "mm_amoeba_wall.frames",                           "1"                             },
+  { "mm_amoeba_wall.growing",                          "RocksMM.png"                   },
+  { "mm_amoeba_wall.growing.xpos",                     "8"                             },
+  { "mm_amoeba_wall.growing.ypos",                     "7"                             },
+  { "mm_amoeba_wall.growing.frames",                   "5"                             },
+  { "mm_amoeba_wall.growing.delay",                    "8"                             },
+  { "mm_amoeba_wall.growing.anim_mode",                        "linear,reverse"                },
+
+  { "mm_pacman",                                       "RocksMM.png"                   },
+  { "mm_pacman.xpos",                                  "0"                             },
+  { "mm_pacman.ypos",                                  "4"                             },
+  { "mm_pacman.frames",                                        "1"                             },
+  { "mm_pacman.right",                                 "RocksMM.png"                   },
+  { "mm_pacman.right.xpos",                            "0"                             },
+  { "mm_pacman.right.ypos",                            "4"                             },
+  { "mm_pacman.right.frames",                          "1"                             },
+  { "mm_pacman.up",                                    "RocksMM.png"                   },
+  { "mm_pacman.up.xpos",                               "1"                             },
+  { "mm_pacman.up.ypos",                               "4"                             },
+  { "mm_pacman.up.frames",                             "1"                             },
+  { "mm_pacman.left",                                  "RocksMM.png"                   },
+  { "mm_pacman.left.xpos",                             "2"                             },
+  { "mm_pacman.left.ypos",                             "4"                             },
+  { "mm_pacman.left.frames",                           "1"                             },
+  { "mm_pacman.down",                                  "RocksMM.png"                   },
+  { "mm_pacman.down.xpos",                             "3"                             },
+  { "mm_pacman.down.ypos",                             "4"                             },
+  { "mm_pacman.down.frames",                           "1"                             },
+  { "mm_pacman.eating.right",                          "RocksMM.png"                   },
+  { "mm_pacman.eating.right.xpos",                     "4"                             },
+  { "mm_pacman.eating.right.ypos",                     "4"                             },
+  { "mm_pacman.eating.right.frames",                   "1"                             },
+  { "mm_pacman.eating.up",                             "RocksMM.png"                   },
+  { "mm_pacman.eating.up.xpos",                                "5"                             },
+  { "mm_pacman.eating.up.ypos",                                "4"                             },
+  { "mm_pacman.eating.up.frames",                      "1"                             },
+  { "mm_pacman.eating.left",                           "RocksMM.png"                   },
+  { "mm_pacman.eating.left.xpos",                      "6"                             },
+  { "mm_pacman.eating.left.ypos",                      "4"                             },
+  { "mm_pacman.eating.left.frames",                    "1"                             },
+  { "mm_pacman.eating.down",                           "RocksMM.png"                   },
+  { "mm_pacman.eating.down.xpos",                      "7"                             },
+  { "mm_pacman.eating.down.ypos",                      "4"                             },
+  { "mm_pacman.eating.down.frames",                    "1"                             },
+
+  { "mm_envelope_1",                                   UNDEFINED_FILENAME              },
+  { "mm_envelope_1.clone_from",                                "envelope_1"                    },
+  { "mm_envelope_1.collecting",                                UNDEFINED_FILENAME              },
+  { "mm_envelope_1.collecting.clone_from",             "envelope_1.collecting"         },
+  { "mm_envelope_2",                                   UNDEFINED_FILENAME              },
+  { "mm_envelope_2.clone_from",                                "envelope_2"                    },
+  { "mm_envelope_2.collecting",                                UNDEFINED_FILENAME              },
+  { "mm_envelope_2.collecting.clone_from",             "envelope_2.collecting"         },
+  { "mm_envelope_3",                                   UNDEFINED_FILENAME              },
+  { "mm_envelope_3.clone_from",                                "envelope_3"                    },
+  { "mm_envelope_3.collecting",                                UNDEFINED_FILENAME              },
+  { "mm_envelope_3.collecting.clone_from",             "envelope_3.collecting"         },
+  { "mm_envelope_4",                                   UNDEFINED_FILENAME              },
+  { "mm_envelope_4.clone_from",                                "envelope_4"                    },
+  { "mm_envelope_4.collecting",                                UNDEFINED_FILENAME              },
+  { "mm_envelope_4.collecting.clone_from",             "envelope_4.collecting"         },
+
+  { "[mm_default].exploding",                          "RocksMM.png"                   },
+  { "[mm_default].exploding.xpos",                     "0"                             },
+  { "[mm_default].exploding.ypos",                     "8"                             },
+  { "[mm_default].exploding.frames",                   "8"                             },
+  { "[mm_default].exploding.delay",                    "2"                             },
+  { "[mm_default].exploding.anim_mode",                        "linear"                        },
+
+  { "df_laser",                                                "RocksDF.png"                   },
+  { "df_laser.xpos",                                   "0"                             },
+  { "df_laser.ypos",                                   "9"                             },
+  { "df_laser.frames",                                 "4"                             },
+  { "df_laser.delay",                                  "8"                             },
+  { "df_laser.right",                                  "RocksDF.png"                   },
+  { "df_laser.right.xpos",                             "0"                             },
+  { "df_laser.right.ypos",                             "9"                             },
+  { "df_laser.right.frames",                           "1"                             },
+  { "df_laser.up",                                     "RocksDF.png"                   },
+  { "df_laser.up.xpos",                                        "1"                             },
+  { "df_laser.up.ypos",                                        "9"                             },
+  { "df_laser.up.frames",                              "1"                             },
+  { "df_laser.left",                                   "RocksDF.png"                   },
+  { "df_laser.left.xpos",                              "2"                             },
+  { "df_laser.left.ypos",                              "9"                             },
+  { "df_laser.left.frames",                            "1"                             },
+  { "df_laser.down",                                   "RocksDF.png"                   },
+  { "df_laser.down.xpos",                              "3"                             },
+  { "df_laser.down.ypos",                              "9"                             },
+  { "df_laser.down.frames",                            "1"                             },
+
+  { "df_receiver",                                     "RocksDF.png"                   },
+  { "df_receiver.xpos",                                        "4"                             },
+  { "df_receiver.ypos",                                        "9"                             },
+  { "df_receiver.frames",                              "4"                             },
+  { "df_receiver.delay",                               "8"                             },
+  { "df_receiver.right",                               "RocksDF.png"                   },
+  { "df_receiver.right.xpos",                          "4"                             },
+  { "df_receiver.right.ypos",                          "9"                             },
+  { "df_receiver.right.frames",                                "1"                             },
+  { "df_receiver.up",                                  "RocksDF.png"                   },
+  { "df_receiver.up.xpos",                             "5"                             },
+  { "df_receiver.up.ypos",                             "9"                             },
+  { "df_receiver.up.frames",                           "1"                             },
+  { "df_receiver.left",                                        "RocksDF.png"                   },
+  { "df_receiver.left.xpos",                           "6"                             },
+  { "df_receiver.left.ypos",                           "9"                             },
+  { "df_receiver.left.frames",                         "1"                             },
+  { "df_receiver.down",                                        "RocksDF.png"                   },
+  { "df_receiver.down.xpos",                           "7"                             },
+  { "df_receiver.down.ypos",                           "9"                             },
+  { "df_receiver.down.frames",                         "1"                             },
+
+  { "df_mirror_1",                                     "RocksDF.png"                   },
+  { "df_mirror_1.xpos",                                        "0"                             },
+  { "df_mirror_1.ypos",                                        "0"                             },
+  { "df_mirror_1.frames",                              "1"                             },
+  { "df_mirror_2",                                     "RocksDF.png"                   },
+  { "df_mirror_2.xpos",                                        "1"                             },
+  { "df_mirror_2.ypos",                                        "0"                             },
+  { "df_mirror_2.frames",                              "1"                             },
+  { "df_mirror_3",                                     "RocksDF.png"                   },
+  { "df_mirror_3.xpos",                                        "2"                             },
+  { "df_mirror_3.ypos",                                        "0"                             },
+  { "df_mirror_3.frames",                              "1"                             },
+  { "df_mirror_4",                                     "RocksDF.png"                   },
+  { "df_mirror_4.xpos",                                        "3"                             },
+  { "df_mirror_4.ypos",                                        "0"                             },
+  { "df_mirror_4.frames",                              "1"                             },
+  { "df_mirror_5",                                     "RocksDF.png"                   },
+  { "df_mirror_5.xpos",                                        "4"                             },
+  { "df_mirror_5.ypos",                                        "0"                             },
+  { "df_mirror_5.frames",                              "1"                             },
+  { "df_mirror_6",                                     "RocksDF.png"                   },
+  { "df_mirror_6.xpos",                                        "5"                             },
+  { "df_mirror_6.ypos",                                        "0"                             },
+  { "df_mirror_6.frames",                              "1"                             },
+  { "df_mirror_7",                                     "RocksDF.png"                   },
+  { "df_mirror_7.xpos",                                        "6"                             },
+  { "df_mirror_7.ypos",                                        "0"                             },
+  { "df_mirror_7.frames",                              "1"                             },
+  { "df_mirror_8",                                     "RocksDF.png"                   },
+  { "df_mirror_8.xpos",                                        "7"                             },
+  { "df_mirror_8.ypos",                                        "0"                             },
+  { "df_mirror_8.frames",                              "1"                             },
+  { "df_mirror_9",                                     "RocksDF.png"                   },
+  { "df_mirror_9.xpos",                                        "8"                             },
+  { "df_mirror_9.ypos",                                        "0"                             },
+  { "df_mirror_9.frames",                              "1"                             },
+  { "df_mirror_10",                                    "RocksDF.png"                   },
+  { "df_mirror_10.xpos",                               "9"                             },
+  { "df_mirror_10.ypos",                               "0"                             },
+  { "df_mirror_10.frames",                             "1"                             },
+  { "df_mirror_11",                                    "RocksDF.png"                   },
+  { "df_mirror_11.xpos",                               "10"                            },
+  { "df_mirror_11.ypos",                               "0"                             },
+  { "df_mirror_11.frames",                             "1"                             },
+  { "df_mirror_12",                                    "RocksDF.png"                   },
+  { "df_mirror_12.xpos",                               "11"                            },
+  { "df_mirror_12.ypos",                               "0"                             },
+  { "df_mirror_12.frames",                             "1"                             },
+  { "df_mirror_13",                                    "RocksDF.png"                   },
+  { "df_mirror_13.xpos",                               "12"                            },
+  { "df_mirror_13.ypos",                               "0"                             },
+  { "df_mirror_13.frames",                             "1"                             },
+  { "df_mirror_14",                                    "RocksDF.png"                   },
+  { "df_mirror_14.xpos",                               "13"                            },
+  { "df_mirror_14.ypos",                               "0"                             },
+  { "df_mirror_14.frames",                             "1"                             },
+  { "df_mirror_15",                                    "RocksDF.png"                   },
+  { "df_mirror_15.xpos",                               "14"                            },
+  { "df_mirror_15.ypos",                               "0"                             },
+  { "df_mirror_15.frames",                             "1"                             },
+  { "df_mirror_16",                                    "RocksDF.png"                   },
+  { "df_mirror_16.xpos",                               "15"                            },
+  { "df_mirror_16.ypos",                               "0"                             },
+  { "df_mirror_16.frames",                             "1"                             },
+
+  { "df_mirror_rotating_1",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_1.xpos",                       "0"                             },
+  { "df_mirror_rotating_1.ypos",                       "0"                             },
+  { "df_mirror_rotating_1.frames",                     "1"                             },
+  { "df_mirror_rotating_1.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_1.EDITOR.xpos",                        "0"                             },
+  { "df_mirror_rotating_1.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_1.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_2",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_2.xpos",                       "1"                             },
+  { "df_mirror_rotating_2.ypos",                       "0"                             },
+  { "df_mirror_rotating_2.frames",                     "1"                             },
+  { "df_mirror_rotating_2.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_2.EDITOR.xpos",                        "1"                             },
+  { "df_mirror_rotating_2.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_2.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_3",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_3.xpos",                       "2"                             },
+  { "df_mirror_rotating_3.ypos",                       "0"                             },
+  { "df_mirror_rotating_3.frames",                     "1"                             },
+  { "df_mirror_rotating_3.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_3.EDITOR.xpos",                        "2"                             },
+  { "df_mirror_rotating_3.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_3.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_4",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_4.xpos",                       "3"                             },
+  { "df_mirror_rotating_4.ypos",                       "0"                             },
+  { "df_mirror_rotating_4.frames",                     "1"                             },
+  { "df_mirror_rotating_4.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_4.EDITOR.xpos",                        "3"                             },
+  { "df_mirror_rotating_4.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_4.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_5",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_5.xpos",                       "4"                             },
+  { "df_mirror_rotating_5.ypos",                       "0"                             },
+  { "df_mirror_rotating_5.frames",                     "1"                             },
+  { "df_mirror_rotating_5.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_5.EDITOR.xpos",                        "4"                             },
+  { "df_mirror_rotating_5.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_5.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_6",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_6.xpos",                       "5"                             },
+  { "df_mirror_rotating_6.ypos",                       "0"                             },
+  { "df_mirror_rotating_6.frames",                     "1"                             },
+  { "df_mirror_rotating_6.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_6.EDITOR.xpos",                        "5"                             },
+  { "df_mirror_rotating_6.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_6.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_7",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_7.xpos",                       "6"                             },
+  { "df_mirror_rotating_7.ypos",                       "0"                             },
+  { "df_mirror_rotating_7.frames",                     "1"                             },
+  { "df_mirror_rotating_7.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_7.EDITOR.xpos",                        "6"                             },
+  { "df_mirror_rotating_7.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_7.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_8",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_8.xpos",                       "7"                             },
+  { "df_mirror_rotating_8.ypos",                       "0"                             },
+  { "df_mirror_rotating_8.frames",                     "1"                             },
+  { "df_mirror_rotating_8.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_8.EDITOR.xpos",                        "7"                             },
+  { "df_mirror_rotating_8.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_8.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_9",                            "RocksDF.png"                   },
+  { "df_mirror_rotating_9.xpos",                       "8"                             },
+  { "df_mirror_rotating_9.ypos",                       "0"                             },
+  { "df_mirror_rotating_9.frames",                     "1"                             },
+  { "df_mirror_rotating_9.EDITOR",                     "RocksDF.png"                   },
+  { "df_mirror_rotating_9.EDITOR.xpos",                        "8"                             },
+  { "df_mirror_rotating_9.EDITOR.ypos",                        "1"                             },
+  { "df_mirror_rotating_9.EDITOR.frames",              "1"                             },
+  { "df_mirror_rotating_10",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_10.xpos",                      "9"                             },
+  { "df_mirror_rotating_10.ypos",                      "0"                             },
+  { "df_mirror_rotating_10.frames",                    "1"                             },
+  { "df_mirror_rotating_10.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_10.EDITOR.xpos",               "9"                             },
+  { "df_mirror_rotating_10.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_10.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_11",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_11.xpos",                      "10"                            },
+  { "df_mirror_rotating_11.ypos",                      "0"                             },
+  { "df_mirror_rotating_11.frames",                    "1"                             },
+  { "df_mirror_rotating_11.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_11.EDITOR.xpos",               "10"                            },
+  { "df_mirror_rotating_11.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_11.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_12",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_12.xpos",                      "11"                            },
+  { "df_mirror_rotating_12.ypos",                      "0"                             },
+  { "df_mirror_rotating_12.frames",                    "1"                             },
+  { "df_mirror_rotating_12.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_12.EDITOR.xpos",               "11"                            },
+  { "df_mirror_rotating_12.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_12.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_13",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_13.xpos",                      "12"                            },
+  { "df_mirror_rotating_13.ypos",                      "0"                             },
+  { "df_mirror_rotating_13.frames",                    "1"                             },
+  { "df_mirror_rotating_13.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_13.EDITOR.xpos",               "12"                            },
+  { "df_mirror_rotating_13.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_13.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_14",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_14.xpos",                      "13"                            },
+  { "df_mirror_rotating_14.ypos",                      "0"                             },
+  { "df_mirror_rotating_14.frames",                    "1"                             },
+  { "df_mirror_rotating_14.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_14.EDITOR.xpos",               "13"                            },
+  { "df_mirror_rotating_14.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_14.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_15",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_15.xpos",                      "14"                            },
+  { "df_mirror_rotating_15.ypos",                      "0"                             },
+  { "df_mirror_rotating_15.frames",                    "1"                             },
+  { "df_mirror_rotating_15.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_15.EDITOR.xpos",               "14"                            },
+  { "df_mirror_rotating_15.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_15.EDITOR.frames",             "1"                             },
+  { "df_mirror_rotating_16",                           "RocksDF.png"                   },
+  { "df_mirror_rotating_16.xpos",                      "15"                            },
+  { "df_mirror_rotating_16.ypos",                      "0"                             },
+  { "df_mirror_rotating_16.frames",                    "1"                             },
+  { "df_mirror_rotating_16.EDITOR",                    "RocksDF.png"                   },
+  { "df_mirror_rotating_16.EDITOR.xpos",               "15"                            },
+  { "df_mirror_rotating_16.EDITOR.ypos",               "1"                             },
+  { "df_mirror_rotating_16.EDITOR.frames",             "1"                             },
+
+  { "df_steel_grid_fixed_1",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_1.xpos",                      "0"                             },
+  { "df_steel_grid_fixed_1.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_1.frames",                    "1"                             },
+  { "df_steel_grid_fixed_2",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_2.xpos",                      "1"                             },
+  { "df_steel_grid_fixed_2.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_2.frames",                    "1"                             },
+  { "df_steel_grid_fixed_3",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_3.xpos",                      "2"                             },
+  { "df_steel_grid_fixed_3.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_3.frames",                    "1"                             },
+  { "df_steel_grid_fixed_4",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_4.xpos",                      "3"                             },
+  { "df_steel_grid_fixed_4.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_4.frames",                    "1"                             },
+  { "df_steel_grid_fixed_5",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_5.xpos",                      "4"                             },
+  { "df_steel_grid_fixed_5.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_5.frames",                    "1"                             },
+  { "df_steel_grid_fixed_6",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_6.xpos",                      "5"                             },
+  { "df_steel_grid_fixed_6.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_6.frames",                    "1"                             },
+  { "df_steel_grid_fixed_7",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_7.xpos",                      "6"                             },
+  { "df_steel_grid_fixed_7.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_7.frames",                    "1"                             },
+  { "df_steel_grid_fixed_8",                           "RocksDF.png"                   },
+  { "df_steel_grid_fixed_8.xpos",                      "7"                             },
+  { "df_steel_grid_fixed_8.ypos",                      "2"                             },
+  { "df_steel_grid_fixed_8.frames",                    "1"                             },
+
+  { "df_wooden_grid_fixed_1",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_1.xpos",                     "8"                             },
+  { "df_wooden_grid_fixed_1.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_1.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_2",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_2.xpos",                     "9"                             },
+  { "df_wooden_grid_fixed_2.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_2.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_3",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_3.xpos",                     "10"                            },
+  { "df_wooden_grid_fixed_3.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_3.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_4",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_4.xpos",                     "11"                            },
+  { "df_wooden_grid_fixed_4.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_4.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_5",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_5.xpos",                     "12"                            },
+  { "df_wooden_grid_fixed_5.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_5.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_6",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_6.xpos",                     "13"                            },
+  { "df_wooden_grid_fixed_6.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_6.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_7",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_7.xpos",                     "14"                            },
+  { "df_wooden_grid_fixed_7.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_7.frames",                   "1"                             },
+  { "df_wooden_grid_fixed_8",                          "RocksDF.png"                   },
+  { "df_wooden_grid_fixed_8.xpos",                     "15"                            },
+  { "df_wooden_grid_fixed_8.ypos",                     "2"                             },
+  { "df_wooden_grid_fixed_8.frames",                   "1"                             },
+
+  { "df_steel_grid_rotating_1",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_1.xpos",                   "0"                             },
+  { "df_steel_grid_rotating_1.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_1.frames",                 "1"                             },
+  { "df_steel_grid_rotating_1.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_1.EDITOR.xpos",            "0"                             },
+  { "df_steel_grid_rotating_1.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_1.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_2",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_2.xpos",                   "1"                             },
+  { "df_steel_grid_rotating_2.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_2.frames",                 "1"                             },
+  { "df_steel_grid_rotating_2.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_2.EDITOR.xpos",            "1"                             },
+  { "df_steel_grid_rotating_2.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_2.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_3",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_3.xpos",                   "2"                             },
+  { "df_steel_grid_rotating_3.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_3.frames",                 "1"                             },
+  { "df_steel_grid_rotating_3.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_3.EDITOR.xpos",            "2"                             },
+  { "df_steel_grid_rotating_3.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_3.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_4",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_4.xpos",                   "3"                             },
+  { "df_steel_grid_rotating_4.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_4.frames",                 "1"                             },
+  { "df_steel_grid_rotating_4.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_4.EDITOR.xpos",            "3"                             },
+  { "df_steel_grid_rotating_4.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_4.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_5",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_5.xpos",                   "4"                             },
+  { "df_steel_grid_rotating_5.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_5.frames",                 "1"                             },
+  { "df_steel_grid_rotating_5.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_5.EDITOR.xpos",            "4"                             },
+  { "df_steel_grid_rotating_5.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_5.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_6",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_6.xpos",                   "5"                             },
+  { "df_steel_grid_rotating_6.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_6.frames",                 "1"                             },
+  { "df_steel_grid_rotating_6.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_6.EDITOR.xpos",            "5"                             },
+  { "df_steel_grid_rotating_6.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_6.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_7",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_7.xpos",                   "6"                             },
+  { "df_steel_grid_rotating_7.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_7.frames",                 "1"                             },
+  { "df_steel_grid_rotating_7.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_7.EDITOR.xpos",            "6"                             },
+  { "df_steel_grid_rotating_7.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_7.EDITOR.frames",          "1"                             },
+  { "df_steel_grid_rotating_8",                                "RocksDF.png"                   },
+  { "df_steel_grid_rotating_8.xpos",                   "7"                             },
+  { "df_steel_grid_rotating_8.ypos",                   "2"                             },
+  { "df_steel_grid_rotating_8.frames",                 "1"                             },
+  { "df_steel_grid_rotating_8.EDITOR",                 "RocksDF.png"                   },
+  { "df_steel_grid_rotating_8.EDITOR.xpos",            "7"                             },
+  { "df_steel_grid_rotating_8.EDITOR.ypos",            "3"                             },
+  { "df_steel_grid_rotating_8.EDITOR.frames",          "1"                             },
+
+  { "df_wooden_grid_rotating_1",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_1.xpos",                  "8"                             },
+  { "df_wooden_grid_rotating_1.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_1.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_1.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_1.EDITOR.xpos",           "8"                             },
+  { "df_wooden_grid_rotating_1.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_1.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_2",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_2.xpos",                  "9"                             },
+  { "df_wooden_grid_rotating_2.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_2.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_2.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_2.EDITOR.xpos",           "9"                             },
+  { "df_wooden_grid_rotating_2.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_2.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_3",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_3.xpos",                  "10"                            },
+  { "df_wooden_grid_rotating_3.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_3.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_3.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_3.EDITOR.xpos",           "10"                            },
+  { "df_wooden_grid_rotating_3.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_3.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_4",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_4.xpos",                  "11"                            },
+  { "df_wooden_grid_rotating_4.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_4.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_4.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_4.EDITOR.xpos",           "11"                            },
+  { "df_wooden_grid_rotating_4.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_4.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_5",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_5.xpos",                  "12"                            },
+  { "df_wooden_grid_rotating_5.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_5.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_5.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_5.EDITOR.xpos",           "12"                            },
+  { "df_wooden_grid_rotating_5.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_5.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_6",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_6.xpos",                  "13"                            },
+  { "df_wooden_grid_rotating_6.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_6.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_6.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_6.EDITOR.xpos",           "13"                            },
+  { "df_wooden_grid_rotating_6.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_6.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_7",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_7.xpos",                  "14"                            },
+  { "df_wooden_grid_rotating_7.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_7.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_7.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_7.EDITOR.xpos",           "14"                            },
+  { "df_wooden_grid_rotating_7.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_7.EDITOR.frames",         "1"                             },
+  { "df_wooden_grid_rotating_8",                       "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_8.xpos",                  "15"                            },
+  { "df_wooden_grid_rotating_8.ypos",                  "2"                             },
+  { "df_wooden_grid_rotating_8.frames",                        "1"                             },
+  { "df_wooden_grid_rotating_8.EDITOR",                        "RocksDF.png"                   },
+  { "df_wooden_grid_rotating_8.EDITOR.xpos",           "15"                            },
+  { "df_wooden_grid_rotating_8.EDITOR.ypos",           "3"                             },
+  { "df_wooden_grid_rotating_8.EDITOR.frames",         "1"                             },
+
+  { "df_fibre_optic_red_1",                            "RocksDF.png"                   },
+  { "df_fibre_optic_red_1.xpos",                       "8"                             },
+  { "df_fibre_optic_red_1.ypos",                       "8"                             },
+  { "df_fibre_optic_red_1.frames",                     "1"                             },
+  { "df_fibre_optic_red_1.EDITOR",                     "RocksDF.png"                   },
+  { "df_fibre_optic_red_1.EDITOR.xpos",                        "8"                             },
+  { "df_fibre_optic_red_1.EDITOR.ypos",                        "9"                             },
+  { "df_fibre_optic_red_1.EDITOR.frames",              "1"                             },
+  { "df_fibre_optic_red_2",                            "RocksDF.png"                   },
+  { "df_fibre_optic_red_2.xpos",                       "9"                             },
+  { "df_fibre_optic_red_2.ypos",                       "8"                             },
+  { "df_fibre_optic_red_2.frames",                     "1"                             },
+  { "df_fibre_optic_red_2.EDITOR",                     "RocksDF.png"                   },
+  { "df_fibre_optic_red_2.EDITOR.xpos",                        "9"                             },
+  { "df_fibre_optic_red_2.EDITOR.ypos",                        "9"                             },
+  { "df_fibre_optic_red_2.EDITOR.frames",              "1"                             },
+  { "df_fibre_optic_yellow_1",                         "RocksDF.png"                   },
+  { "df_fibre_optic_yellow_1.xpos",                    "10"                            },
+  { "df_fibre_optic_yellow_1.ypos",                    "8"                             },
+  { "df_fibre_optic_yellow_1.frames",                  "1"                             },
+  { "df_fibre_optic_yellow_1.EDITOR",                  "RocksDF.png"                   },
+  { "df_fibre_optic_yellow_1.EDITOR.xpos",             "10"                            },
+  { "df_fibre_optic_yellow_1.EDITOR.ypos",             "9"                             },
+  { "df_fibre_optic_yellow_1.EDITOR.frames",           "1"                             },
+  { "df_fibre_optic_yellow_2",                         "RocksDF.png"                   },
+  { "df_fibre_optic_yellow_2.xpos",                    "11"                            },
+  { "df_fibre_optic_yellow_2.ypos",                    "8"                             },
+  { "df_fibre_optic_yellow_2.frames",                  "1"                             },
+  { "df_fibre_optic_yellow_2.EDITOR",                  "RocksDF.png"                   },
+  { "df_fibre_optic_yellow_2.EDITOR.xpos",             "11"                            },
+  { "df_fibre_optic_yellow_2.EDITOR.ypos",             "9"                             },
+  { "df_fibre_optic_yellow_2.EDITOR.frames",           "1"                             },
+  { "df_fibre_optic_green_1",                          "RocksDF.png"                   },
+  { "df_fibre_optic_green_1.xpos",                     "12"                            },
+  { "df_fibre_optic_green_1.ypos",                     "8"                             },
+  { "df_fibre_optic_green_1.frames",                   "1"                             },
+  { "df_fibre_optic_green_1.EDITOR",                   "RocksDF.png"                   },
+  { "df_fibre_optic_green_1.EDITOR.xpos",              "12"                            },
+  { "df_fibre_optic_green_1.EDITOR.ypos",              "9"                             },
+  { "df_fibre_optic_green_1.EDITOR.frames",            "1"                             },
+  { "df_fibre_optic_green_2",                          "RocksDF.png"                   },
+  { "df_fibre_optic_green_2.xpos",                     "13"                            },
+  { "df_fibre_optic_green_2.ypos",                     "8"                             },
+  { "df_fibre_optic_green_2.frames",                   "1"                             },
+  { "df_fibre_optic_green_2.EDITOR",                   "RocksDF.png"                   },
+  { "df_fibre_optic_green_2.EDITOR.xpos",              "13"                            },
+  { "df_fibre_optic_green_2.EDITOR.ypos",              "9"                             },
+  { "df_fibre_optic_green_2.EDITOR.frames",            "1"                             },
+  { "df_fibre_optic_blue_1",                           "RocksDF.png"                   },
+  { "df_fibre_optic_blue_1.xpos",                      "14"                            },
+  { "df_fibre_optic_blue_1.ypos",                      "8"                             },
+  { "df_fibre_optic_blue_1.frames",                    "1"                             },
+  { "df_fibre_optic_blue_1.EDITOR",                    "RocksDF.png"                   },
+  { "df_fibre_optic_blue_1.EDITOR.xpos",               "14"                            },
+  { "df_fibre_optic_blue_1.EDITOR.ypos",               "9"                             },
+  { "df_fibre_optic_blue_1.EDITOR.frames",             "1"                             },
+  { "df_fibre_optic_blue_2",                           "RocksDF.png"                   },
+  { "df_fibre_optic_blue_2.xpos",                      "15"                            },
+  { "df_fibre_optic_blue_2.ypos",                      "8"                             },
+  { "df_fibre_optic_blue_2.frames",                    "1"                             },
+  { "df_fibre_optic_blue_2.EDITOR",                    "RocksDF.png"                   },
+  { "df_fibre_optic_blue_2.EDITOR.xpos",               "15"                            },
+  { "df_fibre_optic_blue_2.EDITOR.ypos",               "9"                             },
+  { "df_fibre_optic_blue_2.EDITOR.frames",             "1"                             },
+
+  { "df_steel_wall",                                   "RocksDF.png"                   },
+  { "df_steel_wall.xpos",                              "6"                             },
+  { "df_steel_wall.ypos",                              "8"                             },
+  { "df_steel_wall.frames",                            "1"                             },
+
+  { "df_wooden_wall",                                  "RocksDF.png"                   },
+  { "df_wooden_wall.xpos",                             "7"                             },
+  { "df_wooden_wall.ypos",                             "8"                             },
+  { "df_wooden_wall.frames",                           "1"                             },
+
+  { "df_refractor",                                    "RocksDF.png"                   },
+  { "df_refractor.xpos",                               "1"                             },
+  { "df_refractor.ypos",                               "8"                             },
+  { "df_refractor.frames",                             "1"                             },
+
+  { "df_cell",                                         "RocksDF.png"                   },
+  { "df_cell.xpos",                                    "2"                             },
+  { "df_cell.ypos",                                    "8"                             },
+  { "df_cell.frames",                                  "1"                             },
+
+  { "df_mine",                                         "RocksDF.png"                   },
+  { "df_mine.xpos",                                    "4"                             },
+  { "df_mine.ypos",                                    "8"                             },
+  { "df_mine.frames",                                  "1"                             },
+  { "df_mine.active",                                  "RocksDF.png"                   },
+  { "df_mine.active.xpos",                             "3"                             },
+  { "df_mine.active.ypos",                             "8"                             },
+  { "df_mine.active.frames",                           "3"                             },
+  { "df_mine.active.delay",                            "6"                             },
+  { "df_mine.active.anim_mode",                                "pingpong"                      },
+
+  { "df_mirror_fixed_1",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_1.xpos",                          "0"                             },
+  { "df_mirror_fixed_1.ypos",                          "10"                            },
+  { "df_mirror_fixed_1.frames",                                "1"                             },
+  { "df_mirror_fixed_2",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_2.xpos",                          "1"                             },
+  { "df_mirror_fixed_2.ypos",                          "10"                            },
+  { "df_mirror_fixed_2.frames",                                "1"                             },
+  { "df_mirror_fixed_3",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_3.xpos",                          "2"                             },
+  { "df_mirror_fixed_3.ypos",                          "10"                            },
+  { "df_mirror_fixed_3.frames",                                "1"                             },
+  { "df_mirror_fixed_4",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_4.xpos",                          "3"                             },
+  { "df_mirror_fixed_4.ypos",                          "10"                            },
+  { "df_mirror_fixed_4.frames",                                "1"                             },
+  { "df_mirror_fixed_5",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_5.xpos",                          "4"                             },
+  { "df_mirror_fixed_5.ypos",                          "10"                            },
+  { "df_mirror_fixed_5.frames",                                "1"                             },
+  { "df_mirror_fixed_6",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_6.xpos",                          "5"                             },
+  { "df_mirror_fixed_6.ypos",                          "10"                            },
+  { "df_mirror_fixed_6.frames",                                "1"                             },
+  { "df_mirror_fixed_7",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_7.xpos",                          "6"                             },
+  { "df_mirror_fixed_7.ypos",                          "10"                            },
+  { "df_mirror_fixed_7.frames",                                "1"                             },
+  { "df_mirror_fixed_8",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_8.xpos",                          "7"                             },
+  { "df_mirror_fixed_8.ypos",                          "10"                            },
+  { "df_mirror_fixed_8.frames",                                "1"                             },
+  { "df_mirror_fixed_9",                               "RocksDF.png"                   },
+  { "df_mirror_fixed_9.xpos",                          "8"                             },
+  { "df_mirror_fixed_9.ypos",                          "10"                            },
+  { "df_mirror_fixed_9.frames",                                "1"                             },
+  { "df_mirror_fixed_10",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_10.xpos",                         "9"                             },
+  { "df_mirror_fixed_10.ypos",                         "10"                            },
+  { "df_mirror_fixed_10.frames",                       "1"                             },
+  { "df_mirror_fixed_11",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_11.xpos",                         "10"                            },
+  { "df_mirror_fixed_11.ypos",                         "10"                            },
+  { "df_mirror_fixed_11.frames",                       "1"                             },
+  { "df_mirror_fixed_12",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_12.xpos",                         "11"                            },
+  { "df_mirror_fixed_12.ypos",                         "10"                            },
+  { "df_mirror_fixed_12.frames",                       "1"                             },
+  { "df_mirror_fixed_13",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_13.xpos",                         "12"                            },
+  { "df_mirror_fixed_13.ypos",                         "10"                            },
+  { "df_mirror_fixed_13.frames",                       "1"                             },
+  { "df_mirror_fixed_14",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_14.xpos",                         "13"                            },
+  { "df_mirror_fixed_14.ypos",                         "10"                            },
+  { "df_mirror_fixed_14.frames",                       "1"                             },
+  { "df_mirror_fixed_15",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_15.xpos",                         "14"                            },
+  { "df_mirror_fixed_15.ypos",                         "10"                            },
+  { "df_mirror_fixed_15.frames",                       "1"                             },
+  { "df_mirror_fixed_16",                              "RocksDF.png"                   },
+  { "df_mirror_fixed_16.xpos",                         "15"                            },
+  { "df_mirror_fixed_16.ypos",                         "10"                            },
+  { "df_mirror_fixed_16.frames",                       "1"                             },
+
+  { "df_slope_1",                                      "RocksDF.png"                   },
+  { "df_slope_1.xpos",                                 "0"                             },
+  { "df_slope_1.ypos",                                 "11"                            },
+  { "df_slope_1.frames",                               "1"                             },
+  { "df_slope_2",                                      "RocksDF.png"                   },
+  { "df_slope_2.xpos",                                 "1"                             },
+  { "df_slope_2.ypos",                                 "11"                            },
+  { "df_slope_2.frames",                               "1"                             },
+  { "df_slope_3",                                      "RocksDF.png"                   },
+  { "df_slope_3.xpos",                                 "2"                             },
+  { "df_slope_3.ypos",                                 "11"                            },
+  { "df_slope_3.frames",                               "1"                             },
+  { "df_slope_4",                                      "RocksDF.png"                   },
+  { "df_slope_4.xpos",                                 "3"                             },
+  { "df_slope_4.ypos",                                 "11"                            },
+  { "df_slope_4.frames",                               "1"                             },
 
   // (these are only defined as elements to support ".PANEL" definitions)
-  { "graphic_1",                               UNDEFINED_FILENAME      },
-  { "graphic_2",                               UNDEFINED_FILENAME      },
-  { "graphic_3",                               UNDEFINED_FILENAME      },
-  { "graphic_4",                               UNDEFINED_FILENAME      },
-  { "graphic_5",                               UNDEFINED_FILENAME      },
-  { "graphic_6",                               UNDEFINED_FILENAME      },
-  { "graphic_7",                               UNDEFINED_FILENAME      },
-  { "graphic_8",                               UNDEFINED_FILENAME      },
+  { "graphic_1",                                       UNDEFINED_FILENAME              },
+  { "graphic_2",                                       UNDEFINED_FILENAME              },
+  { "graphic_3",                                       UNDEFINED_FILENAME              },
+  { "graphic_4",                                       UNDEFINED_FILENAME              },
+  { "graphic_5",                                       UNDEFINED_FILENAME              },
+  { "graphic_6",                                       UNDEFINED_FILENAME              },
+  { "graphic_7",                                       UNDEFINED_FILENAME              },
+  { "graphic_8",                                       UNDEFINED_FILENAME              },
+
+  // game graphics template for level-specific colors for native BD levels
+  { "bdx_game_graphics_color_template",                        UNDEFINED_FILENAME              },
 
 #include "conf_chr.c"  // include auto-generated data structure definitions
 #include "conf_cus.c"  // include auto-generated data structure definitions
 #include "conf_grp.c"  // include auto-generated data structure definitions
+#include "conf_emp.c"  // include auto-generated data structure definitions
 
 
   // ==========================================================================
@@ -5803,1729 +6934,1793 @@ struct ConfigInfo image_config[] =
 
   // keyword to stop parser: "NO_MORE_ELEMENT_IMAGES" <-- do not change!
 
-  { "sp_frame_horizontal",                     "RocksSP.png"           },
-  { "sp_frame_horizontal.xpos",                        "7"                     },
-  { "sp_frame_horizontal.ypos",                        "14"                    },
-  { "sp_frame_vertical",                       "RocksSP.png"           },
-  { "sp_frame_vertical.xpos",                  "6"                     },
-  { "sp_frame_vertical.ypos",                  "14"                    },
-  { "sp_frame_corner",                         "RocksSP.png"           },
-  { "sp_frame_corner.xpos",                    "5"                     },
-  { "sp_frame_corner.ypos",                    "14"                    },
-
-  { "toon_1",                                  "RocksToons.png"        },
-  { "toon_1.x",                                        "2"                     },
-  { "toon_1.y",                                        "72"                    },
-  { "toon_1.width",                            "40"                    },
-  { "toon_1.height",                           "48"                    },
-  { "toon_1.frames",                           "8"                     },
-  { "toon_1.delay",                            "1"                     },
-  { "toon_1.step_offset",                      "4"                     },
-  { "toon_1.step_delay",                       "5"                     },
-  { "toon_1.direction",                                "right"                 },
-  { "toon_1.position",                         "bottom"                },
-
-  { "toon_2",                                  "RocksToons.png"        },
-  { "toon_2.x",                                        "2"                     },
-  { "toon_2.y",                                        "186"                   },
-  { "toon_2.width",                            "40"                    },
-  { "toon_2.height",                           "48"                    },
-  { "toon_2.frames",                           "8"                     },
-  { "toon_2.delay",                            "1"                     },
-  { "toon_2.step_offset",                      "4"                     },
-  { "toon_2.step_delay",                       "5"                     },
-  { "toon_2.direction",                                "left"                  },
-  { "toon_2.position",                         "bottom"                },
-
-  { "toon_3",                                  "RocksToons.png"        },
-  { "toon_3.x",                                        "2"                     },
-  { "toon_3.y",                                        "125"                   },
-  { "toon_3.width",                            "48"                    },
-  { "toon_3.height",                           "56"                    },
-  { "toon_3.frames",                           "8"                     },
-  { "toon_3.delay",                            "1"                     },
-  { "toon_3.step_offset",                      "4"                     },
-  { "toon_3.step_delay",                       "5"                     },
-  { "toon_3.direction",                                "right"                 },
-  { "toon_3.position",                         "bottom"                },
-
-  { "toon_4",                                  "RocksToons.png"        },
-  { "toon_4.x",                                        "327"                   },
-  { "toon_4.y",                                        "10"                    },
-  { "toon_4.width",                            "80"                    },
-  { "toon_4.height",                           "110"                   },
-  { "toon_4.frames",                           "1"                     },
-  { "toon_4.delay",                            "1"                     },
-  { "toon_4.step_offset",                      "1"                     },
-  { "toon_4.step_delay",                       "1"                     },
-  { "toon_4.direction",                                "up"                    },
-  { "toon_4.position",                         "any"                   },
-
-  { "toon_5",                                  "RocksToons.png"        },
-  { "toon_5.x",                                        "2"                     },
-  { "toon_5.y",                                        "2"                     },
-  { "toon_5.width",                            "32"                    },
-  { "toon_5.height",                           "30"                    },
-  { "toon_5.frames",                           "8"                     },
-  { "toon_5.delay",                            "2"                     },
-  { "toon_5.anim_mode",                                "pingpong2"             },
-  { "toon_5.step_offset",                      "2"                     },
-  { "toon_5.step_delay",                       "1"                     },
-  { "toon_5.direction",                                "right"                 },
-  { "toon_5.position",                         "upper"                 },
-
-  { "toon_6",                                  "RocksToons.png"        },
-  { "toon_6.x",                                        "2"                     },
-  { "toon_6.y",                                        "37"                    },
-  { "toon_6.width",                            "32"                    },
-  { "toon_6.height",                           "30"                    },
-  { "toon_6.frames",                           "8"                     },
-  { "toon_6.delay",                            "2"                     },
-  { "toon_6.anim_mode",                                "pingpong2"             },
-  { "toon_6.step_offset",                      "2"                     },
-  { "toon_6.step_delay",                       "1"                     },
-  { "toon_6.direction",                                "left"                  },
-  { "toon_6.position",                         "upper"                 },
-
-  { "toon_7",                                  "RocksMore.png"         },
-  { "toon_7.xpos",                             "0"                     },
-  { "toon_7.ypos",                             "6"                     },
-  { "toon_7.frames",                           "16"                    },
-  { "toon_7.delay",                            "2"                     },
-  { "toon_7.direction",                                "down"                  },
-  { "toon_7.position",                         "any"                   },
-
-  { "toon_8",                                  "RocksHeroes.png"       },
-  { "toon_8.xpos",                             "4"                     },
-  { "toon_8.ypos",                             "1"                     },
-  { "toon_8.frames",                           "4"                     },
-  { "toon_8.delay",                            "4"                     },
-  { "toon_8.direction",                                "right"                 },
-  { "toon_8.position",                         "bottom"                },
-
-  { "toon_9",                                  "RocksHeroes.png"       },
-  { "toon_9.xpos",                             "8"                     },
-  { "toon_9.ypos",                             "7"                     },
-  { "toon_9.frames",                           "4"                     },
-  { "toon_9.delay",                            "2"                     },
-  { "toon_9.direction",                                "left"                  },
-  { "toon_9.position",                         "bottom"                },
-
-  { "toon_10",                                 "RocksHeroes.png"       },
-  { "toon_10.xpos",                            "12"                    },
-  { "toon_10.ypos",                            "7"                     },
-  { "toon_10.frames",                          "4"                     },
-  { "toon_10.delay",                           "2"                     },
-  { "toon_10.direction",                       "right"                 },
-  { "toon_10.position",                                "bottom"                },
-
-  { "toon_11",                                 "RocksHeroes.png"       },
-  { "toon_11.xpos",                            "8"                     },
-  { "toon_11.ypos",                            "5"                     },
-  { "toon_11.frames",                          "4"                     },
-  { "toon_11.delay",                           "2"                     },
-  { "toon_11.direction",                       "left"                  },
-  { "toon_11.position",                                "bottom"                },
-
-  { "toon_12",                                 "RocksHeroes.png"       },
-  { "toon_12.xpos",                            "12"                    },
-  { "toon_12.ypos",                            "5"                     },
-  { "toon_12.frames",                          "4"                     },
-  { "toon_12.delay",                           "2"                     },
-  { "toon_12.direction",                       "right"                 },
-  { "toon_12.position",                                "bottom"                },
-
-  { "toon_13",                                 "RocksHeroes.png"       },
-  { "toon_13.xpos",                            "8"                     },
-  { "toon_13.ypos",                            "1"                     },
-  { "toon_13.frames",                          "4"                     },
-  { "toon_13.delay",                           "2"                     },
-  { "toon_13.direction",                       "left"                  },
-  { "toon_13.position",                                "bottom"                },
-
-  { "toon_14",                                 "RocksHeroes.png"       },
-  { "toon_14.xpos",                            "12"                    },
-  { "toon_14.ypos",                            "1"                     },
-  { "toon_14.frames",                          "4"                     },
-  { "toon_14.delay",                           "2"                     },
-  { "toon_14.direction",                       "right"                 },
-  { "toon_14.position",                                "bottom"                },
-
-  { "toon_15",                                 "RocksHeroes.png"       },
-  { "toon_15.xpos",                            "8"                     },
-  { "toon_15.ypos",                            "3"                     },
-  { "toon_15.frames",                          "4"                     },
-  { "toon_15.delay",                           "2"                     },
-  { "toon_15.direction",                       "left"                  },
-  { "toon_15.position",                                "bottom"                },
-
-  { "toon_16",                                 "RocksHeroes.png"       },
-  { "toon_16.xpos",                            "12"                    },
-  { "toon_16.ypos",                            "3"                     },
-  { "toon_16.frames",                          "4"                     },
-  { "toon_16.delay",                           "2"                     },
-  { "toon_16.direction",                       "right"                 },
-  { "toon_16.position",                                "bottom"                },
-
-  { "toon_17",                                 "RocksHeroes.png"       },
-  { "toon_17.xpos",                            "8"                     },
-  { "toon_17.ypos",                            "9"                     },
-  { "toon_17.frames",                          "8"                     },
-  { "toon_17.delay",                           "2"                     },
-  { "toon_17.direction",                       "left"                  },
-  { "toon_17.position",                                "any"                   },
-
-  { "toon_18",                                 "RocksHeroes.png"       },
-  { "toon_18.xpos",                            "8"                     },
-  { "toon_18.ypos",                            "9"                     },
-  { "toon_18.frames",                          "8"                     },
-  { "toon_18.delay",                           "2"                     },
-  { "toon_18.direction",                       "right"                 },
-  { "toon_18.position",                                "any"                   },
-
-  { "toon_19",                                 "RocksElements.png"     },
-  { "toon_19.xpos",                            "8"                     },
-  { "toon_19.ypos",                            "0"                     },
-  { "toon_19.frames",                          "2"                     },
-  { "toon_19.delay",                           "4"                     },
-  { "toon_19.direction",                       "down"                  },
-  { "toon_19.position",                                "any"                   },
-
-  { "toon_20",                                 "RocksElements.png"     },
-  { "toon_20.xpos",                            "10"                    },
-  { "toon_20.ypos",                            "0"                     },
-  { "toon_20.frames",                          "2"                     },
-  { "toon_20.delay",                           "4"                     },
-  { "toon_20.direction",                       "down"                  },
-  { "toon_20.position",                                "any"                   },
-
-  { "gfx.global.anim_1",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_2",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_3",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_4",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_5",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_6",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_7",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_8",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_9",                       UNDEFINED_FILENAME      },
-  { "gfx.global.anim_10",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_11",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_12",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_13",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_14",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_15",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_16",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_17",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_18",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_19",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_20",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_21",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_22",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_23",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_24",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_25",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_26",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_27",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_28",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_29",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_30",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_31",                      UNDEFINED_FILENAME      },
-  { "gfx.global.anim_32",                      UNDEFINED_FILENAME      },
-
-  { "global.anim_1",                           UNDEFINED_FILENAME      },
-  { "global.anim_2",                           UNDEFINED_FILENAME      },
-  { "global.anim_3",                           UNDEFINED_FILENAME      },
-  { "global.anim_4",                           UNDEFINED_FILENAME      },
-  { "global.anim_5",                           UNDEFINED_FILENAME      },
-  { "global.anim_6",                           UNDEFINED_FILENAME      },
-  { "global.anim_7",                           UNDEFINED_FILENAME      },
-  { "global.anim_8",                           UNDEFINED_FILENAME      },
-  { "global.anim_9",                           UNDEFINED_FILENAME      },
-  { "global.anim_10",                          UNDEFINED_FILENAME      },
-  { "global.anim_11",                          UNDEFINED_FILENAME      },
-  { "global.anim_12",                          UNDEFINED_FILENAME      },
-  { "global.anim_13",                          UNDEFINED_FILENAME      },
-  { "global.anim_14",                          UNDEFINED_FILENAME      },
-  { "global.anim_15",                          UNDEFINED_FILENAME      },
-  { "global.anim_16",                          UNDEFINED_FILENAME      },
-  { "global.anim_17",                          UNDEFINED_FILENAME      },
-  { "global.anim_18",                          UNDEFINED_FILENAME      },
-  { "global.anim_19",                          UNDEFINED_FILENAME      },
-  { "global.anim_20",                          UNDEFINED_FILENAME      },
-  { "global.anim_21",                          UNDEFINED_FILENAME      },
-  { "global.anim_22",                          UNDEFINED_FILENAME      },
-  { "global.anim_23",                          UNDEFINED_FILENAME      },
-  { "global.anim_24",                          UNDEFINED_FILENAME      },
-  { "global.anim_25",                          UNDEFINED_FILENAME      },
-  { "global.anim_26",                          UNDEFINED_FILENAME      },
-  { "global.anim_27",                          UNDEFINED_FILENAME      },
-  { "global.anim_28",                          UNDEFINED_FILENAME      },
-  { "global.anim_29",                          UNDEFINED_FILENAME      },
-  { "global.anim_30",                          UNDEFINED_FILENAME      },
-  { "global.anim_31",                          UNDEFINED_FILENAME      },
-  { "global.anim_32",                          UNDEFINED_FILENAME      },
-
-  { "internal.global.toon_default",            UNDEFINED_FILENAME      },
-  { "internal.global.toon_default.anim_mode",  "random"                },
-
-  { "internal.global.anim_default",            UNDEFINED_FILENAME      },
-
-  { "menu.calibrate_red",                      "RocksElements.png"     },
-  { "menu.calibrate_red.xpos",                 "12"                    },
-  { "menu.calibrate_red.ypos",                 "8"                     },
-  { "menu.calibrate_red.frames",               "1"                     },
-  { "menu.calibrate_blue",                     "RocksElements.png"     },
-  { "menu.calibrate_blue.xpos",                        "13"                    },
-  { "menu.calibrate_blue.ypos",                        "8"                     },
-  { "menu.calibrate_blue.frames",              "1"                     },
-  { "menu.calibrate_yellow",                   "RocksElements.png"     },
-  { "menu.calibrate_yellow.xpos",              "14"                    },
-  { "menu.calibrate_yellow.ypos",              "8"                     },
-  { "menu.calibrate_yellow.frames",            "1"                     },
-
-  { "menu.button",                             "RocksElements.png"     },
-  { "menu.button.xpos",                                "13"                    },
-  { "menu.button.ypos",                                "8"                     },
-  { "menu.button.frames",                      "1"                     },
-  { "menu.button.active",                      "RocksElements.png"     },
-  { "menu.button.active.xpos",                 "12"                    },
-  { "menu.button.active.ypos",                 "8"                     },
-  { "menu.button.active.frames",               "1"                     },
-
-  { "menu.button_left",                                "RocksDC.png"           },
-  { "menu.button_left.xpos",                   "8"                     },
-  { "menu.button_left.ypos",                   "8"                     },
-  { "menu.button_left.frames",                 "1"                     },
-  { "menu.button_left.active",                 "RocksDC.png"           },
-  { "menu.button_left.active.xpos",            "8"                     },
-  { "menu.button_left.active.ypos",            "9"                     },
-  { "menu.button_left.active.frames",          "1"                     },
-  { "menu.button_right",                       "RocksDC.png"           },
-  { "menu.button_right.xpos",                  "9"                     },
-  { "menu.button_right.ypos",                  "8"                     },
-  { "menu.button_right.frames",                        "1"                     },
-  { "menu.button_right.active",                        "RocksDC.png"           },
-  { "menu.button_right.active.xpos",           "9"                     },
-  { "menu.button_right.active.ypos",           "9"                     },
-  { "menu.button_right.active.frames",         "1"                     },
-  { "menu.button_up",                          "RocksDC.png"           },
-  { "menu.button_up.xpos",                     "10"                    },
-  { "menu.button_up.ypos",                     "8"                     },
-  { "menu.button_up.frames",                   "1"                     },
-  { "menu.button_up.active",                   "RocksDC.png"           },
-  { "menu.button_up.active.xpos",              "10"                    },
-  { "menu.button_up.active.ypos",              "9"                     },
-  { "menu.button_up.active.frames",            "1"                     },
-  { "menu.button_down",                                "RocksDC.png"           },
-  { "menu.button_down.xpos",                   "11"                    },
-  { "menu.button_down.ypos",                   "8"                     },
-  { "menu.button_down.frames",                 "1"                     },
-  { "menu.button_down.active",                 "RocksDC.png"           },
-  { "menu.button_down.active.xpos",            "11"                    },
-  { "menu.button_down.active.ypos",            "9"                     },
-  { "menu.button_down.active.frames",          "1"                     },
-
-  { "menu.button_enter_menu",                  UNDEFINED_FILENAME      },
-  { "menu.button_enter_menu.clone_from",       "menu.button_right"     },
-  { "menu.button_enter_menu.active",           UNDEFINED_FILENAME      },
-  { "menu.button_enter_menu.active.clone_from",        "menu.button_right.active" },
-  { "menu.button_leave_menu",                  UNDEFINED_FILENAME      },
-  { "menu.button_leave_menu.clone_from",       "menu.button_left"      },
-  { "menu.button_leave_menu.active",           UNDEFINED_FILENAME      },
-  { "menu.button_leave_menu.active.clone_from",        "menu.button_left.active" },
-
-  { "menu.button_next_level",                  UNDEFINED_FILENAME      },
-  { "menu.button_next_level.clone_from",       "menu.button_right"     },
-  { "menu.button_next_level.active",           UNDEFINED_FILENAME      },
-  { "menu.button_next_level.active.clone_from",        "menu.button_right.active" },
-  { "menu.button_prev_level",                  UNDEFINED_FILENAME      },
-  { "menu.button_prev_level.clone_from",       "menu.button_left"      },
-  { "menu.button_prev_level.active",           UNDEFINED_FILENAME      },
-  { "menu.button_prev_level.active.clone_from",        "menu.button_left.active" },
-
-  { "menu.button_name",                                UNDEFINED_FILENAME      },
-  { "menu.button_name.clone_from",             "menu.button"           },
-  { "menu.button_name.active",                 UNDEFINED_FILENAME      },
-  { "menu.button_name.active.clone_from",      "menu.button.active"    },
-  { "menu.button_levels",                      UNDEFINED_FILENAME      },
-  { "menu.button_levels.clone_from",           "menu.button_right"     },
-  { "menu.button_levels.active",               UNDEFINED_FILENAME      },
-  { "menu.button_levels.active.clone_from",    "menu.button_right.active" },
-  { "menu.button_scores",                      UNDEFINED_FILENAME      },
-  { "menu.button_scores.clone_from",           "menu.button"           },
-  { "menu.button_scores.active",               UNDEFINED_FILENAME      },
-  { "menu.button_scores.active.clone_from",    "menu.button.active"    },
-  { "menu.button_editor",                      UNDEFINED_FILENAME      },
-  { "menu.button_editor.clone_from",           "menu.button"           },
-  { "menu.button_editor.active",               UNDEFINED_FILENAME      },
-  { "menu.button_editor.active.clone_from",    "menu.button.active"    },
-  { "menu.button_info",                                UNDEFINED_FILENAME      },
-  { "menu.button_info.clone_from",             "menu.button_right"     },
-  { "menu.button_info.active",                 UNDEFINED_FILENAME      },
-  { "menu.button_info.active.clone_from",      "menu.button_right.active" },
-  { "menu.button_game",                                UNDEFINED_FILENAME      },
-  { "menu.button_game.clone_from",             "menu.button"           },
-  { "menu.button_game.active",                 UNDEFINED_FILENAME      },
-  { "menu.button_game.active.clone_from",      "menu.button.active"    },
-  { "menu.button_setup",                       UNDEFINED_FILENAME      },
-  { "menu.button_setup.clone_from",            "menu.button_right"     },
-  { "menu.button_setup.active",                        UNDEFINED_FILENAME      },
-  { "menu.button_setup.active.clone_from",     "menu.button_right.active" },
-  { "menu.button_quit",                                UNDEFINED_FILENAME      },
-  { "menu.button_quit.clone_from",             "menu.button"           },
-  { "menu.button_quit.active",                 UNDEFINED_FILENAME      },
-  { "menu.button_quit.active.clone_from",      "menu.button.active"    },
-
-  { "menu.button_first_level",                 UNDEFINED_FILENAME      },
-  { "menu.button_first_level.active",          UNDEFINED_FILENAME      },
-  { "menu.button_last_level",                  UNDEFINED_FILENAME      },
-  { "menu.button_last_level.active",           UNDEFINED_FILENAME      },
-  { "menu.button_level_number",                        UNDEFINED_FILENAME      },
-  { "menu.button_level_number.active",         UNDEFINED_FILENAME      },
-
-  { "menu.button_insert_solution",             UNDEFINED_FILENAME      },
-  { "menu.button_insert_solution.active",      UNDEFINED_FILENAME      },
-  { "menu.button_play_solution",               UNDEFINED_FILENAME      },
-  { "menu.button_play_solution.active",                UNDEFINED_FILENAME      },
-
-  { "menu.button_switch_ecs_aga",              UNDEFINED_FILENAME      },
-  { "menu.button_switch_ecs_aga.active",       UNDEFINED_FILENAME      },
-
-  { "menu.button_touch_back",                  "RocksTouch.png"        },
-  { "menu.button_touch_back.x",                        "210"                   },
-  { "menu.button_touch_back.y",                        "180"                   },
-  { "menu.button_touch_back.width",            "60"                    },
-  { "menu.button_touch_back.height",           "60"                    },
-  { "menu.button_touch_back.pressed_xoffset",  "-200"                  },
-  { "menu.button_touch_next",                  "RocksTouch.png"        },
-  { "menu.button_touch_next.x",                        "330"                   },
-  { "menu.button_touch_next.y",                        "180"                   },
-  { "menu.button_touch_next.width",            "60"                    },
-  { "menu.button_touch_next.height",           "60"                    },
-  { "menu.button_touch_next.pressed_xoffset",  "-200"                  },
-  { "menu.button_touch_back2",                 "RocksTouch.png"        },
-  { "menu.button_touch_back2.x",               "210"                   },
-  { "menu.button_touch_back2.y",               "180"                   },
-  { "menu.button_touch_back2.width",           "60"                    },
-  { "menu.button_touch_back2.height",          "60"                    },
-  { "menu.button_touch_back2.pressed_xoffset", "-200"                  },
-  { "menu.button_touch_next2",                 "RocksTouch.png"        },
-  { "menu.button_touch_next2.x",               "330"                   },
-  { "menu.button_touch_next2.y",               "180"                   },
-  { "menu.button_touch_next2.width",           "60"                    },
-  { "menu.button_touch_next2.height",          "60"                    },
-  { "menu.button_touch_next2.pressed_xoffset", "-200"                  },
-
-  { "menu.scrollbar",                          "RocksDC.png"           },
-  { "menu.scrollbar.xpos",                     "8"                     },
-  { "menu.scrollbar.ypos",                     "10"                    },
-  { "menu.scrollbar.frames",                   "1"                     },
-  { "menu.scrollbar.active",                   "RocksDC.png"           },
-  { "menu.scrollbar.active.xpos",              "9"                     },
-  { "menu.scrollbar.active.ypos",              "10"                    },
-  { "menu.scrollbar.active.frames",            "1"                     },
-
-  { "gfx.game.panel.time_anim",                        "RocksDoorMM.png"       },
-  { "gfx.game.panel.time_anim.x",              "5"                     },
-  { "gfx.game.panel.time_anim.y",              "0"                     },
-  { "gfx.game.panel.time_anim.width",          "90"                    },
-  { "gfx.game.panel.time_anim.height",         "35"                    },
-  { "gfx.game.panel.time_anim.frames",         "1"                     },
-  { "gfx.game.panel.time_anim.active",         "RocksDoorMM.png"       },
-  { "gfx.game.panel.time_anim.active.x",       "105"                   },
-  { "gfx.game.panel.time_anim.active.y",       "0"                     },
-  { "gfx.game.panel.time_anim.active.width",   "90"                    },
-  { "gfx.game.panel.time_anim.active.height",  "35"                    },
-  { "gfx.game.panel.time_anim.active.frames",  "1"                     },
-
-  { "gfx.game.panel.health_anim",              "RocksDoorMM.png"       },
-  { "gfx.game.panel.health_anim.x",            "5"                     },
-  { "gfx.game.panel.health_anim.y",            "35"                    },
-  { "gfx.game.panel.health_anim.width",                "90"                    },
-  { "gfx.game.panel.health_anim.height",       "35"                    },
-  { "gfx.game.panel.health_anim.frames",       "1"                     },
-  { "gfx.game.panel.health_anim.active",       "RocksDoorMM.png"       },
-  { "gfx.game.panel.health_anim.active.x",     "105"                   },
-  { "gfx.game.panel.health_anim.active.y",     "35"                    },
-  { "gfx.game.panel.health_anim.active.width", "90"                    },
-  { "gfx.game.panel.health_anim.active.height",        "35"                    },
-  { "gfx.game.panel.health_anim.active.frames",        "1"                     },
-
-  { "gfx.game.button.stop",                    "RocksDoor.png"         },
-  { "gfx.game.button.stop.x",                  "305"                   },
-  { "gfx.game.button.stop.y",                  "185"                   },
-  { "gfx.game.button.stop.width",              "30"                    },
-  { "gfx.game.button.stop.height",             "30"                    },
-  { "gfx.game.button.stop.pressed_xoffset",    "-100"                  },
-  { "gfx.game.button.pause",                   "RocksDoor.png"         },
-  { "gfx.game.button.pause.x",                 "335"                   },
-  { "gfx.game.button.pause.y",                 "185"                   },
-  { "gfx.game.button.pause.width",             "30"                    },
-  { "gfx.game.button.pause.height",            "30"                    },
-  { "gfx.game.button.pause.pressed_xoffset",   "-100"                  },
-  { "gfx.game.button.play",                    "RocksDoor.png"         },
-  { "gfx.game.button.play.x",                  "365"                   },
-  { "gfx.game.button.play.y",                  "185"                   },
-  { "gfx.game.button.play.width",              "30"                    },
-  { "gfx.game.button.play.height",             "30"                    },
-  { "gfx.game.button.play.pressed_xoffset",    "-100"                  },
-
-  { "gfx.game.button.undo",                    "RocksDoor2.png"        },
-  { "gfx.game.button.undo.x",                  "105"                   },
-  { "gfx.game.button.undo.y",                  "20"                    },
-  { "gfx.game.button.undo.width",              "30"                    },
-  { "gfx.game.button.undo.height",             "30"                    },
-  { "gfx.game.button.undo.pressed_xoffset",    "-100"                  },
-  { "gfx.game.button.redo",                    "RocksDoor2.png"        },
-  { "gfx.game.button.redo.x",                  "165"                   },
-  { "gfx.game.button.redo.y",                  "20"                    },
-  { "gfx.game.button.redo.width",              "30"                    },
-  { "gfx.game.button.redo.height",             "30"                    },
-  { "gfx.game.button.redo.pressed_xoffset",    "-100"                  },
-
-  { "gfx.game.button.save",                    "RocksDoor2.png"        },
-  { "gfx.game.button.save.x",                  "105"                   },
-  { "gfx.game.button.save.y",                  "50"                    },
-  { "gfx.game.button.save.width",              "30"                    },
-  { "gfx.game.button.save.height",             "30"                    },
-  { "gfx.game.button.save.pressed_xoffset",    "-100"                  },
-  { "gfx.game.button.pause2",                  "RocksDoor2.png"        },
-  { "gfx.game.button.pause2.x",                        "135"                   },
-  { "gfx.game.button.pause2.y",                        "50"                    },
-  { "gfx.game.button.pause2.width",            "30"                    },
-  { "gfx.game.button.pause2.height",           "30"                    },
-  { "gfx.game.button.pause2.pressed_xoffset",  "-100"                  },
-  { "gfx.game.button.pause2.active_yoffset",   "-30"                   },
-  { "gfx.game.button.load",                    "RocksDoor2.png"        },
-  { "gfx.game.button.load.x",                  "165"                   },
-  { "gfx.game.button.load.y",                  "50"                    },
-  { "gfx.game.button.load.width",              "30"                    },
-  { "gfx.game.button.load.height",             "30"                    },
-  { "gfx.game.button.load.pressed_xoffset",    "-100"                  },
-
-  { "gfx.game.button.sound_music",             "RocksDoor.png"         },
-  { "gfx.game.button.sound_music.x",           "305"                   },
-  { "gfx.game.button.sound_music.y",           "245"                   },
-  { "gfx.game.button.sound_music.width",       "30"                    },
-  { "gfx.game.button.sound_music.height",      "30"                    },
-  { "gfx.game.button.sound_music.pressed_xoffset", "-100"              },
-  { "gfx.game.button.sound_music.active_yoffset", "-30"                        },
-  { "gfx.game.button.sound_loops",             "RocksDoor.png"         },
-  { "gfx.game.button.sound_loops.x",           "335"                   },
-  { "gfx.game.button.sound_loops.y",           "245"                   },
-  { "gfx.game.button.sound_loops.width",       "30"                    },
-  { "gfx.game.button.sound_loops.height",      "30"                    },
-  { "gfx.game.button.sound_loops.pressed_xoffset", "-100"              },
-  { "gfx.game.button.sound_loops.active_yoffset", "-30"                        },
-  { "gfx.game.button.sound_simple",            "RocksDoor.png"         },
-  { "gfx.game.button.sound_simple.x",          "365"                   },
-  { "gfx.game.button.sound_simple.y",          "245"                   },
-  { "gfx.game.button.sound_simple.width",      "30"                    },
-  { "gfx.game.button.sound_simple.height",     "30"                    },
-  { "gfx.game.button.sound_simple.pressed_xoffset", "-100"             },
-  { "gfx.game.button.sound_simple.active_yoffset", "-30"               },
-
-  { "gfx.game.button.panel_stop",              UNDEFINED_FILENAME      },
-  { "gfx.game.button.panel_pause",             UNDEFINED_FILENAME      },
-  { "gfx.game.button.panel_play",              UNDEFINED_FILENAME      },
-
-  { "gfx.game.button.panel_sound_music",       UNDEFINED_FILENAME      },
-  { "gfx.game.button.panel_sound_loops",       UNDEFINED_FILENAME      },
-  { "gfx.game.button.panel_sound_simple",      UNDEFINED_FILENAME      },
-
-  { "gfx.game.button.touch_stop",              "RocksTouch.png"        },
-  { "gfx.game.button.touch_stop.x",            "210"                   },
-  { "gfx.game.button.touch_stop.y",            "120"                   },
-  { "gfx.game.button.touch_stop.width",                "60"                    },
-  { "gfx.game.button.touch_stop.height",       "60"                    },
-  { "gfx.game.button.touch_stop.pressed_xoffset", "-200"               },
-  { "gfx.game.button.touch_pause",             "RocksTouch.png"        },
-  { "gfx.game.button.touch_pause.x",           "270"                   },
-  { "gfx.game.button.touch_pause.y",           "120"                   },
-  { "gfx.game.button.touch_pause.width",       "60"                    },
-  { "gfx.game.button.touch_pause.height",      "60"                    },
-  { "gfx.game.button.touch_pause.pressed_xoffset", "-200"              },
-  { "gfx.game.button.touch_pause.active_yoffset", "60"                 },
-
-  { "gfx.tape.button.eject",                   "RocksDoor.png"         },
-  { "gfx.tape.button.eject.x",                 "305"                   },
-  { "gfx.tape.button.eject.y",                 "357"                   },
-  { "gfx.tape.button.eject.width",             "18"                    },
-  { "gfx.tape.button.eject.height",            "18"                    },
-  { "gfx.tape.button.eject.pressed_xoffset",   "-100"                  },
-  { "gfx.tape.button.extra",                   "RocksDoor.png"         },
-  { "gfx.tape.button.extra.x",                 "505"                   },
-  { "gfx.tape.button.extra.y",                 "357"                   },
-  { "gfx.tape.button.extra.width",             "18"                    },
-  { "gfx.tape.button.extra.height",            "18"                    },
-  { "gfx.tape.button.extra.pressed_xoffset",   "-100"                  },
-  { "gfx.tape.button.stop",                    "RocksDoor.png"         },
-  { "gfx.tape.button.stop.x",                  "323"                   },
-  { "gfx.tape.button.stop.y",                  "357"                   },
-  { "gfx.tape.button.stop.width",              "18"                    },
-  { "gfx.tape.button.stop.height",             "18"                    },
-  { "gfx.tape.button.stop.pressed_xoffset",    "-100"                  },
-  { "gfx.tape.button.pause",                   "RocksDoor.png"         },
-  { "gfx.tape.button.pause.x",                 "341"                   },
-  { "gfx.tape.button.pause.y",                 "357"                   },
-  { "gfx.tape.button.pause.width",             "18"                    },
-  { "gfx.tape.button.pause.height",            "18"                    },
-  { "gfx.tape.button.pause.pressed_xoffset",   "-100"                  },
-  { "gfx.tape.button.record",                  "RocksDoor.png"         },
-  { "gfx.tape.button.record.x",                        "359"                   },
-  { "gfx.tape.button.record.y",                        "357"                   },
-  { "gfx.tape.button.record.width",            "18"                    },
-  { "gfx.tape.button.record.height",           "18"                    },
-  { "gfx.tape.button.record.pressed_xoffset",  "-100"                  },
-  { "gfx.tape.button.play",                    "RocksDoor.png"         },
-  { "gfx.tape.button.play.x",                  "377"                   },
-  { "gfx.tape.button.play.y",                  "357"                   },
-  { "gfx.tape.button.play.width",              "18"                    },
-  { "gfx.tape.button.play.height",             "18"                    },
-  { "gfx.tape.button.play.pressed_xoffset",    "-100"                  },
-
-  { "gfx.tape.button.insert_solution",         UNDEFINED_FILENAME      },
-  { "gfx.tape.button.play_solution",           UNDEFINED_FILENAME      },
-
-  { "gfx.tape.symbol.eject",                   UNDEFINED_FILENAME      },
-  { "gfx.tape.symbol.stop",                    UNDEFINED_FILENAME      },
-  { "gfx.tape.symbol.pause",                   "RocksDoor.png"         },
-  { "gfx.tape.symbol.pause.x",                 "340"                   },
-  { "gfx.tape.symbol.pause.y",                 "321"                   },
-  { "gfx.tape.symbol.pause.width",             "17"                    },
-  { "gfx.tape.symbol.pause.height",            "13"                    },
-  { "gfx.tape.symbol.record",                  "RocksDoor.png"         },
-  { "gfx.tape.symbol.record.x",                        "325"                   },
-  { "gfx.tape.symbol.record.y",                        "321"                   },
-  { "gfx.tape.symbol.record.width",            "16"                    },
-  { "gfx.tape.symbol.record.height",           "16"                    },
-  { "gfx.tape.symbol.play",                    "RocksDoor.png"         },
-  { "gfx.tape.symbol.play.x",                  "357"                   },
-  { "gfx.tape.symbol.play.y",                  "321"                   },
-  { "gfx.tape.symbol.play.width",              "11"                    },
-  { "gfx.tape.symbol.play.height",             "13"                    },
-  { "gfx.tape.symbol.fast_forward",            "RocksDoor.png"         },
-  { "gfx.tape.symbol.fast_forward.x",          "539"                   },
-  { "gfx.tape.symbol.fast_forward.y",          "193"                   },
-  { "gfx.tape.symbol.fast_forward.width",      "27"                    },
-  { "gfx.tape.symbol.fast_forward.height",     "13"                    },
-  { "gfx.tape.symbol.warp_forward",            "RocksDoor.png"         },
-  { "gfx.tape.symbol.warp_forward.x",          "539"                   },
-  { "gfx.tape.symbol.warp_forward.y",          "152"                   },
-  { "gfx.tape.symbol.warp_forward.width",      "27"                    },
-  { "gfx.tape.symbol.warp_forward.height",     "13"                    },
-  { "gfx.tape.symbol.warp_forward_blind",      "RocksDoor.png"         },
-  { "gfx.tape.symbol.warp_forward_blind.x",    "539"                   },
-  { "gfx.tape.symbol.warp_forward_blind.y",    "165"                   },
-  { "gfx.tape.symbol.warp_forward_blind.width",        "27"                    },
-  { "gfx.tape.symbol.warp_forward_blind.height","13"                   },
-  { "gfx.tape.symbol.pause_before_end",                "RocksDoor.png"         },
-  { "gfx.tape.symbol.pause_before_end.x",      "539"                   },
-  { "gfx.tape.symbol.pause_before_end.y",      "221"                   },
-  { "gfx.tape.symbol.pause_before_end.width",  "27"                    },
-  { "gfx.tape.symbol.pause_before_end.height", "13"                    },
-  { "gfx.tape.symbol.single_step",             UNDEFINED_FILENAME      },
-
-  { "gfx.tape.label.eject",                    UNDEFINED_FILENAME      },
-  { "gfx.tape.label.stop",                     UNDEFINED_FILENAME      },
-  { "gfx.tape.label.pause",                    "RocksDoor.png"         },
-  { "gfx.tape.label.pause.x",                  "305"                   },
-  { "gfx.tape.label.pause.y",                  "341"                   },
-  { "gfx.tape.label.pause.width",              "35"                    },
-  { "gfx.tape.label.pause.height",             "8"                     },
-  { "gfx.tape.label.record",                   "RocksDoor.png"         },
-  { "gfx.tape.label.record.x",                 "305"                   },
-  { "gfx.tape.label.record.y",                 "321"                   },
-  { "gfx.tape.label.record.width",             "20"                    },
-  { "gfx.tape.label.record.height",            "12"                    },
-  { "gfx.tape.label.play",                     "RocksDoor.png"         },
-  { "gfx.tape.label.play.x",                   "370"                   },
-  { "gfx.tape.label.play.y",                   "321"                   },
-  { "gfx.tape.label.play.width",               "22"                    },
-  { "gfx.tape.label.play.height",              "12"                    },
-  { "gfx.tape.label.fast_forward",             "RocksDoor.png"         },
-  { "gfx.tape.label.fast_forward.x",           "505"                   },
-  { "gfx.tape.label.fast_forward.y",           "193"                   },
-  { "gfx.tape.label.fast_forward.width",       "40"                    },
-  { "gfx.tape.label.fast_forward.height",      "28"                    },
-  { "gfx.tape.label.warp_forward",             "RocksDoor.png"         },
-  { "gfx.tape.label.warp_forward.x",           "505"                   },
-  { "gfx.tape.label.warp_forward.y",           "165"                   },
-  { "gfx.tape.label.warp_forward.width",       "40"                    },
-  { "gfx.tape.label.warp_forward.height",      "28"                    },
-  { "gfx.tape.label.warp_forward_blind",       "RocksDoor.png"         },
-  { "gfx.tape.label.warp_forward_blind.x",     "505"                   },
-  { "gfx.tape.label.warp_forward_blind.y",     "165"                   },
-  { "gfx.tape.label.warp_forward_blind.width", "40"                    },
-  { "gfx.tape.label.warp_forward_blind.height",        "28"                    },
-  { "gfx.tape.label.pause_before_end",         "RocksDoor.png"         },
-  { "gfx.tape.label.pause_before_end.x",       "505"                   },
-  { "gfx.tape.label.pause_before_end.y",       "221"                   },
-  { "gfx.tape.label.pause_before_end.width",   "40"                    },
-  { "gfx.tape.label.pause_before_end.height",  "28"                    },
-  { "gfx.tape.label.single_step",              "RocksDoor.png"         },
-  { "gfx.tape.label.single_step.x",            "557"                   },
-  { "gfx.tape.label.single_step.y",            "139"                   },
-  { "gfx.tape.label.single_step.width",                "38"                    },
-  { "gfx.tape.label.single_step.height",       "13"                    },
-
-  { "gfx.tape.label.date",                     "RocksDoor.png"         },
-  { "gfx.tape.label.date.x",                   "305"                   },
-  { "gfx.tape.label.date.y",                   "285"                   },
-  { "gfx.tape.label.date.width",               "90"                    },
-  { "gfx.tape.label.date.height",              "31"                    },
-  { "gfx.tape.label.time",                     "RocksDoor.png"         },
-  { "gfx.tape.label.time.x",                   "346"                   },
-  { "gfx.tape.label.time.y",                   "335"                   },
-  { "gfx.tape.label.time.width",               "45"                    },
-  { "gfx.tape.label.time.height",              "13"                    },
-
-  { "gfx.request.button.yes",                  "RocksDoor.png"         },
-  { "gfx.request.button.yes.x",                        "302"                   },
-  { "gfx.request.button.yes.y",                        "0"                     },
-  { "gfx.request.button.yes.width",            "46"                    },
-  { "gfx.request.button.yes.height",           "28"                    },
-  { "gfx.request.button.yes.pressed_xoffset",  "-100"                  },
-  { "gfx.request.button.no",                   "RocksDoor.png"         },
-  { "gfx.request.button.no.x",                 "352"                   },
-  { "gfx.request.button.no.y",                 "0"                     },
-  { "gfx.request.button.no.width",             "46"                    },
-  { "gfx.request.button.no.height",            "28"                    },
-  { "gfx.request.button.no.pressed_xoffset",   "-100"                  },
-  { "gfx.request.button.confirm",              "RocksDoor.png"         },
-  { "gfx.request.button.confirm.x",            "302"                   },
-  { "gfx.request.button.confirm.y",            "30"                    },
-  { "gfx.request.button.confirm.width",                "96"                    },
-  { "gfx.request.button.confirm.height",       "28"                    },
-  { "gfx.request.button.confirm.pressed_xoffset", "-100"               },
-  { "gfx.request.button.player_1",             "RocksDoor.png"         },
-  { "gfx.request.button.player_1.x",           "305"                   },
-  { "gfx.request.button.player_1.y",           "185"                   },
-  { "gfx.request.button.player_1.width",       "30"                    },
-  { "gfx.request.button.player_1.height",      "30"                    },
-  { "gfx.request.button.player_1.pressed_xoffset", "-100"              },
-  { "gfx.request.button.player_2",             UNDEFINED_FILENAME      },
-  { "gfx.request.button.player_2.clone_from",  "gfx.request.button.player_1" },
-  { "gfx.request.button.player_3",             UNDEFINED_FILENAME      },
-  { "gfx.request.button.player_3.clone_from",  "gfx.request.button.player_1" },
-  { "gfx.request.button.player_4",             UNDEFINED_FILENAME      },
-  { "gfx.request.button.player_4.clone_from",  "gfx.request.button.player_1" },
-
-  { "gfx.request.button.touch_yes",            "RocksTouch.png"        },
-  { "gfx.request.button.touch_yes.x",          "204"                   },
-  { "gfx.request.button.touch_yes.y",          "0"                     },
-  { "gfx.request.button.touch_yes.width",      "92"                    },
-  { "gfx.request.button.touch_yes.height",     "56"                    },
-  { "gfx.request.button.touch_yes.pressed_xoffset", "-200"             },
-  { "gfx.request.button.touch_no",             "RocksTouch.png"        },
-  { "gfx.request.button.touch_no.x",           "304"                   },
-  { "gfx.request.button.touch_no.y",           "0"                     },
-  { "gfx.request.button.touch_no.width",       "92"                    },
-  { "gfx.request.button.touch_no.height",      "56"                    },
-  { "gfx.request.button.touch_no.pressed_xoffset", "-200"              },
-  { "gfx.request.button.touch_confirm",                "RocksTouch.png"        },
-  { "gfx.request.button.touch_confirm.x",      "204"                   },
-  { "gfx.request.button.touch_confirm.y",      "60"                    },
-  { "gfx.request.button.touch_confirm.width",  "192"                   },
-  { "gfx.request.button.touch_confirm.height", "56"                    },
-  { "gfx.request.button.touch_confirm.pressed_xoffset", "-200"         },
-
-  { "font.initial_1",                          "RocksFontSmall.png"    },
-  { "font.initial_1.x",                                "0"                     },
-  { "font.initial_1.y",                                "0"                     },
-  { "font.initial_1.width",                    "14"                    },
-  { "font.initial_1.height",                   "14"                    },
-  { "font.initial_2",                          "RocksFontSmall.png"    },
-  { "font.initial_2.x",                                "0"                     },
-  { "font.initial_2.y",                                "70"                    },
-  { "font.initial_2.width",                    "14"                    },
-  { "font.initial_2.height",                   "14"                    },
-  { "font.initial_3",                          "RocksFontSmall.png"    },
-  { "font.initial_3.x",                                "0"                     },
-  { "font.initial_3.y",                                "140"                   },
-  { "font.initial_3.width",                    "14"                    },
-  { "font.initial_3.height",                   "14"                    },
-  { "font.initial_4",                          "RocksFontSmall.png"    },
-  { "font.initial_4.x",                                "0"                     },
-  { "font.initial_4.y",                                "210"                   },
-  { "font.initial_4.width",                    "14"                    },
-  { "font.initial_4.height",                   "14"                    },
-
-  { "font.title_1",                            "RocksFontBig.png"      },
-  { "font.title_1.x",                          "0"                     },
-  { "font.title_1.y",                          "480"                   },
-  { "font.title_1.width",                      "32"                    },
-  { "font.title_1.height",                     "32"                    },
-  { "font.title_2",                            "RocksFontSmall.png"    },
-  { "font.title_2.x",                          "0"                     },
-  { "font.title_2.y",                          "0"                     },
-  { "font.title_2.width",                      "14"                    },
-  { "font.title_2.height",                     "14"                    },
-  { "font.title_2.SETUP",                      UNDEFINED_FILENAME      },
-  { "font.title_2.SETUP.clone_from",           "font.text_2"           },
-
-  { "font.menu_1",                             "RocksFontBig.png"      },
-  { "font.menu_1.x",                           "0"                     },
-  { "font.menu_1.y",                           "320"                   },
-  { "font.menu_1.width",                       "32"                    },
-  { "font.menu_1.height",                      "32"                    },
-  { "font.menu_1.active",                      "RocksFontBig.png"      },
-  { "font.menu_1.active.x",                    "0"                     },
-  { "font.menu_1.active.y",                    "480"                   },
-  { "font.menu_1.active.width",                        "32"                    },
-  { "font.menu_1.active.height",               "32"                    },
-  { "font.menu_2",                             "RocksFontMedium.png"   },
-  { "font.menu_2.x",                           "0"                     },
-  { "font.menu_2.y",                           "320"                   },
-  { "font.menu_2.width",                       "16"                    },
-  { "font.menu_2.height",                      "32"                    },
-  { "font.menu_2.active",                      "RocksFontMedium.png"   },
-  { "font.menu_2.active.x",                    "0"                     },
-  { "font.menu_2.active.y",                    "480"                   },
-  { "font.menu_2.active.width",                        "16"                    },
-  { "font.menu_2.active.height",               "32"                    },
-
-  { "font.text_1",                             "RocksFontSmall.png"    },
-  { "font.text_1.x",                           "0"                     },
-  { "font.text_1.y",                           "140"                   },
-  { "font.text_1.width",                       "14"                    },
-  { "font.text_1.height",                      "14"                    },
-  { "font.text_1.MAIN",                                UNDEFINED_FILENAME      },
-  { "font.text_1.MAIN.clone_from",             "font.text_1.PREVIEW"   },
-  { "font.text_1.LEVELS",                      "RocksFontMedium.png"   },
-  { "font.text_1.LEVELS.x",                    "0"                     },
-  { "font.text_1.LEVELS.y",                    "0"                     },
-  { "font.text_1.LEVELS.width",                        "16"                    },
-  { "font.text_1.LEVELS.height",               "32"                    },
-  { "font.text_1.LEVELNR",                     UNDEFINED_FILENAME      },
-  { "font.text_1.LEVELNR.clone_from",          "font.text_1.LEVELS"    },
-  { "font.text_1.SETUP",                       UNDEFINED_FILENAME      },
-  { "font.text_1.SETUP.clone_from",            "font.text_1.LEVELS"    },
-  { "font.text_1.NAMES",                       UNDEFINED_FILENAME      },
-  { "font.text_1.NAMES.clone_from",            "font.input_1.MAIN"     },
-  { "font.text_1.PREVIEW",                     "RocksFontEM.png"       },
-  { "font.text_1.PREVIEW.x",                   "0"                     },
-  { "font.text_1.PREVIEW.y",                   "160"                   },
-  { "font.text_1.PREVIEW.width",               "16"                    },
-  { "font.text_1.PREVIEW.height",              "16"                    },
-  { "font.text_1.SCORES",                      "RocksFontMedium.png"   },
-  { "font.text_1.SCORES.x",                    "0"                     },
-  { "font.text_1.SCORES.y",                    "480"                   },
-  { "font.text_1.SCORES.width",                        "16"                    },
-  { "font.text_1.SCORES.height",               "32"                    },
-  { "font.text_1.active.SCORES",               "RocksFontMedium.png"   },
-  { "font.text_1.active.SCORES.x",             "0"                     },
-  { "font.text_1.active.SCORES.y",             "0"                     },
-  { "font.text_1.active.SCORES.width",         "16"                    },
-  { "font.text_1.active.SCORES.height",                "32"                    },
-  { "font.text_1.PANEL",                       UNDEFINED_FILENAME      },
-  { "font.text_1.PANEL.clone_from",            "font.level_number"     },
-  { "font.text_1.DOOR",                                UNDEFINED_FILENAME      },
-  { "font.text_1.DOOR.clone_from",             "font.level_number"     },
-  { "font.text_2",                             "RocksFontSmall.png"    },
-  { "font.text_2.x",                           "0"                     },
-  { "font.text_2.y",                           "210"                   },
-  { "font.text_2.width",                       "14"                    },
-  { "font.text_2.height",                      "14"                    },
-  { "font.text_2.MAIN",                                UNDEFINED_FILENAME      },
-  { "font.text_2.MAIN.clone_from",             "font.text_2.PREVIEW"   },
-  { "font.text_2.LEVELS",                      "RocksFontMedium.png"   },
-  { "font.text_2.LEVELS.x",                    "0"                     },
-  { "font.text_2.LEVELS.y",                    "160"                   },
-  { "font.text_2.LEVELS.width",                        "16"                    },
-  { "font.text_2.LEVELS.height",               "32"                    },
-  { "font.text_2.LEVELNR",                     UNDEFINED_FILENAME      },
-  { "font.text_2.LEVELNR.clone_from",          "font.text_2.LEVELS"    },
-  { "font.text_2.SETUP",                       UNDEFINED_FILENAME      },
-  { "font.text_2.SETUP.clone_from",            "font.text_2.LEVELS"    },
-  { "font.text_2.NAMES",                       UNDEFINED_FILENAME      },
-  { "font.text_2.NAMES.clone_from",            "font.option_off"       },
-  { "font.text_2.PREVIEW",                     "RocksFontEM.png"       },
-  { "font.text_2.PREVIEW.x",                   "0"                     },
-  { "font.text_2.PREVIEW.y",                   "160"                   },
-  { "font.text_2.PREVIEW.width",               "16"                    },
-  { "font.text_2.PREVIEW.height",              "16"                    },
-  { "font.text_2.SCORES",                      "RocksFontBig.png"      },
-  { "font.text_2.SCORES.x",                    "0"                     },
-  { "font.text_2.SCORES.y",                    "320"                   },
-  { "font.text_2.SCORES.width",                        "32"                    },
-  { "font.text_2.SCORES.height",               "32"                    },
-  { "font.text_2.active.SCORES",               "RocksFontBig.png"      },
-  { "font.text_2.active.SCORES.x",             "0"                     },
-  { "font.text_2.active.SCORES.y",             "0"                     },
-  { "font.text_2.active.SCORES.width",         "32"                    },
-  { "font.text_2.active.SCORES.height",                "32"                    },
-  { "font.text_3",                             "RocksFontSmall.png"    },
-  { "font.text_3.x",                           "0"                     },
-  { "font.text_3.y",                           "0"                     },
-  { "font.text_3.width",                       "14"                    },
-  { "font.text_3.height",                      "14"                    },
-  { "font.text_3.LEVELS",                      "RocksFontMedium.png"   },
-  { "font.text_3.LEVELS.x",                    "0"                     },
-  { "font.text_3.LEVELS.y",                    "320"                   },
-  { "font.text_3.LEVELS.width",                        "16"                    },
-  { "font.text_3.LEVELS.height",               "32"                    },
-  { "font.text_3.LEVELNR",                     UNDEFINED_FILENAME      },
-  { "font.text_3.LEVELNR.clone_from",          "font.text_3.LEVELS"    },
-  { "font.text_3.SETUP",                       UNDEFINED_FILENAME      },
-  { "font.text_3.SETUP.clone_from",            "font.text_3.LEVELS"    },
-  { "font.text_3.NAMES",                       UNDEFINED_FILENAME      },
-  { "font.text_3.NAMES.clone_from",            "font.menu_1"           },
-  { "font.text_3.PREVIEW",                     "RocksFontEM.png"       },
-  { "font.text_3.PREVIEW.x",                   "0"                     },
-  { "font.text_3.PREVIEW.y",                   "160"                   },
-  { "font.text_3.PREVIEW.width",               "16"                    },
-  { "font.text_3.PREVIEW.height",              "16"                    },
-  { "font.text_3.SCORES",                      "RocksFontMedium.png"   },
-  { "font.text_3.SCORES.x",                    "0"                     },
-  { "font.text_3.SCORES.y",                    "480"                   },
-  { "font.text_3.SCORES.width",                        "16"                    },
-  { "font.text_3.SCORES.height",               "32"                    },
-  { "font.text_3.active.SCORES",               "RocksFontMedium.png"   },
-  { "font.text_3.active.SCORES.x",             "0"                     },
-  { "font.text_3.active.SCORES.y",             "0"                     },
-  { "font.text_3.active.SCORES.width",         "16"                    },
-  { "font.text_3.active.SCORES.height",                "32"                    },
-  { "font.text_4",                             "RocksFontSmall.png"    },
-  { "font.text_4.x",                           "0"                     },
-  { "font.text_4.y",                           "70"                    },
-  { "font.text_4.width",                       "14"                    },
-  { "font.text_4.height",                      "14"                    },
-  { "font.text_4.MAIN",                                UNDEFINED_FILENAME      },
-  { "font.text_4.MAIN.clone_from",             "font.text_3.PREVIEW"   },
-  { "font.text_4.LEVELS",                      "RocksFontMedium.png"   },
-  { "font.text_4.LEVELS.x",                    "0"                     },
-  { "font.text_4.LEVELS.y",                    "480"                   },
-  { "font.text_4.LEVELS.width",                        "16"                    },
-  { "font.text_4.LEVELS.height",               "32"                    },
-  { "font.text_4.LEVELNR",                     UNDEFINED_FILENAME      },
-  { "font.text_4.LEVELNR.clone_from",          "font.text_4.LEVELS"    },
-  { "font.text_4.SETUP",                       UNDEFINED_FILENAME      },
-  { "font.text_4.SETUP.clone_from",            "font.text_4.LEVELS"    },
-  { "font.text_4.NAMES",                       UNDEFINED_FILENAME      },
-  { "font.text_4.NAMES.clone_from",            "font.menu_1.active"    },
-  { "font.text_4.SCORES",                      "RocksFontMedium.png"   },
-  { "font.text_4.SCORES.x",                    "0"                     },
-  { "font.text_4.SCORES.y",                    "480"                   },
-  { "font.text_4.SCORES.width",                        "16"                    },
-  { "font.text_4.SCORES.height",               "32"                    },
-  { "font.text_4.active.SCORES",               "RocksFontMedium.png"   },
-  { "font.text_4.active.SCORES.x",             "0"                     },
-  { "font.text_4.active.SCORES.y",             "0"                     },
-  { "font.text_4.active.SCORES.width",         "16"                    },
-  { "font.text_4.active.SCORES.height",                "32"                    },
-
-  { "font.envelope_1",                         "RocksFontEM.png"       },
-  { "font.envelope_1.x",                       "0"                     },
-  { "font.envelope_1.y",                       "160"                   },
-  { "font.envelope_1.width",                   "16"                    },
-  { "font.envelope_1.height",                  "16"                    },
-  { "font.envelope_2",                         "RocksFontEM.png"       },
-  { "font.envelope_2.x",                       "0"                     },
-  { "font.envelope_2.y",                       "160"                   },
-  { "font.envelope_2.width",                   "16"                    },
-  { "font.envelope_2.height",                  "16"                    },
-  { "font.envelope_3",                         "RocksFontEM.png"       },
-  { "font.envelope_3.x",                       "0"                     },
-  { "font.envelope_3.y",                       "160"                   },
-  { "font.envelope_3.width",                   "16"                    },
-  { "font.envelope_3.height",                  "16"                    },
-  { "font.envelope_4",                         "RocksFontEM.png"       },
-  { "font.envelope_4.x",                       "0"                     },
-  { "font.envelope_4.y",                       "160"                   },
-  { "font.envelope_4.width",                   "16"                    },
-  { "font.envelope_4.height",                  "16"                    },
-
-  { "font.request",                            "RocksFontSmall.png"    },
-  { "font.request.x",                          "0"                     },
-  { "font.request.y",                          "210"                   },
-  { "font.request.width",                      "14"                    },
-  { "font.request.height",                     "14"                    },
-
-  { "font.input_1",                            "RocksFontSmall.png"    },
-  { "font.input_1.x",                          "0"                     },
-  { "font.input_1.y",                          "210"                   },
-  { "font.input_1.width",                      "14"                    },
-  { "font.input_1.height",                     "14"                    },
-  { "font.input_1.MAIN",                       "RocksFontBig.png"      },
-  { "font.input_1.MAIN.x",                     "0"                     },
-  { "font.input_1.MAIN.y",                     "0"                     },
-  { "font.input_1.MAIN.width",                 "32"                    },
-  { "font.input_1.MAIN.height",                        "32"                    },
-  { "font.input_1.NAMES",                      UNDEFINED_FILENAME      },
-  { "font.input_1.NAMES.clone_from",           "font.input_1.MAIN"     },
-  { "font.input_1.active",                     "RocksFontSmall.png"    },
-  { "font.input_1.active.x",                   "0"                     },
-  { "font.input_1.active.y",                   "210"                   },
-  { "font.input_1.active.width",               "14"                    },
-  { "font.input_1.active.height",              "14"                    },
-  { "font.input_1.active.MAIN",                        "RocksFontBig.png"      },
-  { "font.input_1.active.MAIN.x",              "0"                     },
-  { "font.input_1.active.MAIN.y",              "480"                   },
-  { "font.input_1.active.MAIN.width",          "32"                    },
-  { "font.input_1.active.MAIN.height",         "32"                    },
-  { "font.input_1.active.NAMES",               UNDEFINED_FILENAME      },
-  { "font.input_1.active.NAMES.clone_from",    "font.input_1.active.MAIN" },
-  { "font.input_1.active.SETUP",               "RocksFontBig.png"      },
-  { "font.input_1.active.SETUP.x",             "0"                     },
-  { "font.input_1.active.SETUP.y",             "0"                     },
-  { "font.input_1.active.SETUP.width",         "32"                    },
-  { "font.input_1.active.SETUP.height",                "32"                    },
-  { "font.input_2",                            "RocksFontSmall.png"    },
-  { "font.input_2.x",                          "0"                     },
-  { "font.input_2.y",                          "210"                   },
-  { "font.input_2.width",                      "14"                    },
-  { "font.input_2.height",                     "14"                    },
-  { "font.input_2.active",                     "RocksFontSmall.png"    },
-  { "font.input_2.active.x",                   "0"                     },
-  { "font.input_2.active.y",                   "210"                   },
-  { "font.input_2.active.width",               "14"                    },
-  { "font.input_2.active.height",              "14"                    },
-
-  { "font.option_off",                         "RocksFontBig.png"      },
-  { "font.option_off.x",                       "0"                     },
-  { "font.option_off.y",                       "160"                   },
-  { "font.option_off.width",                   "32"                    },
-  { "font.option_off.height",                  "32"                    },
-  { "font.option_off_narrow",                  UNDEFINED_FILENAME      },
-  { "font.option_off_narrow.clone_from",       "font.text_2.LEVELS"    },
-  { "font.option_on",                          "RocksFontBig.png"      },
-  { "font.option_on.x",                                "0"                     },
-  { "font.option_on.y",                                "480"                   },
-  { "font.option_on.width",                    "32"                    },
-  { "font.option_on.height",                   "32"                    },
-  { "font.option_on_narrow",                   UNDEFINED_FILENAME      },
-  { "font.option_on_narrow.clone_from",                "font.text_4.LEVELS"    },
-
-  { "font.value_1",                            "RocksFontBig.png"      },
-  { "font.value_1.x",                          "0"                     },
-  { "font.value_1.y",                          "480"                   },
-  { "font.value_1.width",                      "32"                    },
-  { "font.value_1.height",                     "32"                    },
-  { "font.value_2",                            "RocksFontMedium.png"   },
-  { "font.value_2.x",                          "0"                     },
-  { "font.value_2.y",                          "480"                   },
-  { "font.value_2.width",                      "16"                    },
-  { "font.value_2.height",                     "32"                    },
-  { "font.value_old",                          "RocksFontBig.png"      },
-  { "font.value_old.x",                                "0"                     },
-  { "font.value_old.y",                                "160"                   },
-  { "font.value_old.width",                    "32"                    },
-  { "font.value_old.height",                   "32"                    },
-  { "font.value_old_narrow",                   UNDEFINED_FILENAME      },
-  { "font.value_old_narrow.clone_from",                "font.text_2.LEVELS"    },
-  { "font.value_narrow",                       UNDEFINED_FILENAME      },
-  { "font.value_narrow.clone_from",            "font.text_4.LEVELS"    },
-
-  { "font.level_number",                       "RocksFontSmall.png"    },
-  { "font.level_number.x",                     "0"                     },
-  { "font.level_number.y",                     "350"                   },
-  { "font.level_number.width",                 "10"                    },
-  { "font.level_number.height",                        "14"                    },
-  { "font.level_number.active",                        UNDEFINED_FILENAME      },
-  { "font.level_number.active.clone_from",     "font.level_number"     },
-
-  { "font.tape_recorder",                      "RocksFontSmall.png"    },
-  { "font.tape_recorder.x",                    "0"                     },
-  { "font.tape_recorder.y",                    "280"                   },
-  { "font.tape_recorder.width",                        "11"                    },
-  { "font.tape_recorder.height",               "14"                    },
-
-  { "font.game_info",                          "RocksFontEM.png"       },
-  { "font.game_info.xpos",                     "0"                     },
-  { "font.game_info.ypos",                     "0"                     },
-  { "font.game_info.delay",                    "10"                    },
-
-  { "font.info.elements",                      UNDEFINED_FILENAME      },
-  { "font.info.elements.clone_from",           "font.level_number"     },
-
-  { "font.info.levelset",                      UNDEFINED_FILENAME      },
-  { "font.info.levelset.clone_from",           "font.level_number"     },
-
-  { "font.main.network_players",               UNDEFINED_FILENAME      },
-  { "font.main.network_players.clone_from",    "font.level_number"     },
-
-  { "editor.element_border",                   "RocksMore.png"         },
-  { "editor.element_border.xpos",              "0"                     },
-  { "editor.element_border.ypos",              "2"                     },
-  { "editor.element_border.border_size",       "8"                     },
-
-  { "editor.element_border_input",             "RocksMore.png"         },
-  { "editor.element_border_input.xpos",                "10"                    },
-  { "editor.element_border_input.ypos",                "7"                     },
-  { "editor.element_border_input.border_size", "4"                     },
-
-  { "editor.counter.down",                     "RocksDoor.png"         },
-  { "editor.counter.down.x",                   "302"                   },
-  { "editor.counter.down.y",                   "60"                    },
-  { "editor.counter.down.width",               "20"                    },
-  { "editor.counter.down.height",              "20"                    },
-  { "editor.counter.down.pressed_xoffset",     "-100"                  },
-
-  { "editor.counter.up",                       "RocksDoor.png"         },
-  { "editor.counter.up.x",                     "378"                   },
-  { "editor.counter.up.y",                     "60"                    },
-  { "editor.counter.up.width",                 "20"                    },
-  { "editor.counter.up.height",                        "20"                    },
-  { "editor.counter.up.pressed_xoffset",       "-100"                  },
-
-  { "editor.counter.input",                    "RocksDoor.png"         },
-  { "editor.counter.input.x",                  "324"                   },
-  { "editor.counter.input.y",                  "60"                    },
-  { "editor.counter.input.width",              "52"                    },
-  { "editor.counter.input.height",             "20"                    },
-  { "editor.counter.input.active_xoffset",     "-100"                  },
-  { "editor.counter.input.border_size",                "3"                     },
-
-  { "editor.selectbox.input",                  "RocksDoor.png"         },
-  { "editor.selectbox.input.x",                        "324"                   },
-  { "editor.selectbox.input.y",                        "82"                    },
-  { "editor.selectbox.input.width",            "52"                    },
-  { "editor.selectbox.input.height",           "20"                    },
-  { "editor.selectbox.input.active_xoffset",   "-100"                  },
-  { "editor.selectbox.input.border_size",      "3"                     },
-
-  { "editor.selectbox.button",                 UNDEFINED_FILENAME      },
-  { "editor.selectbox.button.width",           "14"                    },
-
-  { "editor.checkbox",                         "RocksDoor.png"         },
-  { "editor.checkbox.x",                       "302"                   },
-  { "editor.checkbox.y",                       "82"                    },
-  { "editor.checkbox.width",                   "20"                    },
-  { "editor.checkbox.height",                  "20"                    },
-  { "editor.checkbox.pressed_xoffset",         "-100"                  },
-  { "editor.checkbox.active_xoffset",          "76"                    },
-
-  { "editor.radiobutton",                      "RocksDoor.png"         },
-  { "editor.radiobutton.x",                    "302"                   },
-  { "editor.radiobutton.y",                    "104"                   },
-  { "editor.radiobutton.width",                        "20"                    },
-  { "editor.radiobutton.height",               "20"                    },
-  { "editor.radiobutton.pressed_xoffset",      "-100"                  },
-  { "editor.radiobutton.active_xoffset",       "76"                    },
-
-  { "editor.stickybutton",                     "RocksDoor.png"         },
-  { "editor.stickybutton.x",                   "302"                   },
-  { "editor.stickybutton.y",                   "126"                   },
-  { "editor.stickybutton.width",               "20"                    },
-  { "editor.stickybutton.height",              "20"                    },
-  { "editor.stickybutton.pressed_xoffset",     "-100"                  },
-  { "editor.stickybutton.active_xoffset",      "76"                    },
-
-  { "editor.tabbutton",                                "RocksDoor.png"         },
-  { "editor.tabbutton.x",                      "324"                   },
-  { "editor.tabbutton.y",                      "104"                   },
-  { "editor.tabbutton.width",                  "52"                    },
-  { "editor.tabbutton.height",                 "20"                    },
-  { "editor.tabbutton.pressed_xoffset",                "-100"                  },
-  { "editor.tabbutton.active_yoffset",         "22"                    },
-  { "editor.tabbutton.border_size",            "3"                     },
-  { "editor.tabbutton.draw_xoffset",           "2"                     },
-
-  { "editor.textbutton",                       "RocksDoor.png"         },
-  { "editor.textbutton.x",                     "324"                   },
-  { "editor.textbutton.y",                     "148"                   },
-  { "editor.textbutton.width",                 "52"                    },
-  { "editor.textbutton.height",                        "20"                    },
-  { "editor.textbutton.pressed_xoffset",       "-100"                  },
-  { "editor.textbutton.border_size",           "3"                     },
-  { "editor.textbutton.draw_xoffset",          "2"                     },
-
-  { "editor.input.text",                       "RocksDoor.png"         },
-  { "editor.input.text.x",                     "324"                   },
-  { "editor.input.text.y",                     "60"                    },
-  { "editor.input.text.width",                 "52"                    },
-  { "editor.input.text.height",                        "20"                    },
-  { "editor.input.text.active_xoffset",                "-100"                  },
-  { "editor.input.text.border_size",           "3"                     },
-
-  { "editor.input.textarea",                   "RocksDoor.png"         },
-  { "editor.input.textarea.x",                 "324"                   },
-  { "editor.input.textarea.y",                 "60"                    },
-  { "editor.input.textarea.width",             "52"                    },
-  { "editor.input.textarea.height",            "20"                    },
-  { "editor.input.textarea.active_xoffset",    "-100"                  },
-  { "editor.input.textarea.border_size",       "3"                     },
-
-  { "editor.cascade_list",                     "RocksMore.png"         },
-  { "editor.cascade_list.xpos",                        "9"                     },
-  { "editor.cascade_list.ypos",                        "8"                     },
-  { "editor.cascade_list.frames",              "1"                     },
-  { "editor.cascade_list.active",              "RocksMore.png"         },
-  { "editor.cascade_list.active.xpos",         "10"                    },
-  { "editor.cascade_list.active.ypos",         "8"                     },
-  { "editor.cascade_list.active.frames",       "1"                     },
-
-  { "editor.palette.button",                   "RocksDoor.png"         },
-  { "editor.palette.button.x",                 "525"                   },
-  { "editor.palette.button.y",                 "30"                    },
-  { "editor.palette.button.width",             "20"                    },
-  { "editor.palette.button.height",            "20"                    },
-  { "editor.palette.button.pressed_xoffset",   "-20"                   },
-
-  { "editor.palette.scroll_up",                        "RocksDoor.png"         },
-  { "editor.palette.scroll_up.x",              "750"                   },
-  { "editor.palette.scroll_up.y",              "0"                     },
-  { "editor.palette.scroll_up.width",          "10"                    },
-  { "editor.palette.scroll_up.height",         "10"                    },
-  { "editor.palette.scroll_up.pressed_xoffset",        "-10"                   },
-
-  { "editor.palette.scroll_down",              "RocksDoor.png"         },
-  { "editor.palette.scroll_down.x",            "750"                   },
-  { "editor.palette.scroll_down.y",            "10"                    },
-  { "editor.palette.scroll_down.width",                "10"                    },
-  { "editor.palette.scroll_down.height",       "10"                    },
-  { "editor.palette.scroll_down.pressed_xoffset", "-10"                        },
-
-  { "editor.palette.scrollbar",                        "RocksDoor.png"         },
-  { "editor.palette.scrollbar.x",              "750"                   },
-  { "editor.palette.scrollbar.y",              "20"                    },
-  { "editor.palette.scrollbar.width",          "10"                    },
-  { "editor.palette.scrollbar.height",         "10"                    },
-  { "editor.palette.scrollbar.pressed_xoffset",        "-10"                   },
-  { "editor.palette.scrollbar.border_size",    "3"                     },
-
-  { "editor.playfield.scroll_up",              "RocksDoor.png"         },
-  { "editor.playfield.scroll_up.x",            "724"                   },
-  { "editor.playfield.scroll_up.y",            "0"                     },
-  { "editor.playfield.scroll_up.width",                "16"                    },
-  { "editor.playfield.scroll_up.height",       "16"                    },
-  { "editor.playfield.scroll_up.pressed_xoffset", "-16"                        },
-
-  { "editor.playfield.scroll_down",            "RocksDoor.png"         },
-  { "editor.playfield.scroll_down.x",          "724"                   },
-  { "editor.playfield.scroll_down.y",          "16"                    },
-  { "editor.playfield.scroll_down.width",      "16"                    },
-  { "editor.playfield.scroll_down.height",     "16"                    },
-  { "editor.playfield.scroll_down.pressed_xoffset", "-16"              },
-
-  { "editor.playfield.scroll_left",            "RocksDoor.png"         },
-  { "editor.playfield.scroll_left.x",          "724"                   },
-  { "editor.playfield.scroll_left.y",          "32"                    },
-  { "editor.playfield.scroll_left.width",      "16"                    },
-  { "editor.playfield.scroll_left.height",     "16"                    },
-  { "editor.playfield.scroll_left.pressed_xoffset", "-16"              },
-
-  { "editor.playfield.scroll_right",           "RocksDoor.png"         },
-  { "editor.playfield.scroll_right.x",         "724"                   },
-  { "editor.playfield.scroll_right.y",         "48"                    },
-  { "editor.playfield.scroll_right.width",     "16"                    },
-  { "editor.playfield.scroll_right.height",    "16"                    },
-  { "editor.playfield.scroll_right.pressed_xoffset", "-16"             },
-
-  { "editor.playfield.scrollbar",              "RocksDoor.png"         },
-  { "editor.playfield.scrollbar.x",            "724"                   },
-  { "editor.playfield.scrollbar.y",            "64"                    },
-  { "editor.playfield.scrollbar.width",                "16"                    },
-  { "editor.playfield.scrollbar.height",       "16"                    },
-  { "editor.playfield.scrollbar.pressed_xoffset", "-16"                        },
-  { "editor.playfield.scrollbar.border_size",  "3"                     },
-
-  { "gfx.editor.button.prev_level",            "RocksDoor.png"         },
-  { "gfx.editor.button.prev_level.x",          "724"                   },
-  { "gfx.editor.button.prev_level.y",          "32"                    },
-  { "gfx.editor.button.prev_level.width",      "16"                    },
-  { "gfx.editor.button.prev_level.height",     "16"                    },
-  { "gfx.editor.button.prev_level.pressed_xoffset", "-16"              },
-
-  { "gfx.editor.button.next_level",            "RocksDoor.png"         },
-  { "gfx.editor.button.next_level.x",          "724"                   },
-  { "gfx.editor.button.next_level.y",          "48"                    },
-  { "gfx.editor.button.next_level.width",      "16"                    },
-  { "gfx.editor.button.next_level.height",     "16"                    },
-  { "gfx.editor.button.next_level.pressed_xoffset", "-16"              },
-
-  { "gfx.editor.button.properties",            "RocksDoor2.png"        },
-  { "gfx.editor.button.properties.x",          "105"                   },
-  { "gfx.editor.button.properties.y",          "0"                     },
-  { "gfx.editor.button.properties.width",      "90"                    },
-  { "gfx.editor.button.properties.height",     "20"                    },
-  { "gfx.editor.button.properties.pressed_xoffset", "-100"             },
-
-  { "gfx.editor.button.element_left",          "RocksDoor2.png"        },
-  { "gfx.editor.button.element_left.x",                "368"                   },
-  { "gfx.editor.button.element_left.y",                "48"                    },
-  { "gfx.editor.button.element_left.width",    "16"                    },
-  { "gfx.editor.button.element_left.height",   "16"                    },
-  { "gfx.editor.button.element_left.pressed_xoffset", "0"              },
-
-  { "gfx.editor.button.element_middle",                "RocksDoor2.png"        },
-  { "gfx.editor.button.element_middle.x",      "368"                   },
-  { "gfx.editor.button.element_middle.y",      "48"                    },
-  { "gfx.editor.button.element_middle.width",  "16"                    },
-  { "gfx.editor.button.element_middle.height", "16"                    },
-  { "gfx.editor.button.element_middle.pressed_xoffset", "0"            },
-
-  { "gfx.editor.button.element_right",         "RocksDoor2.png"        },
-  { "gfx.editor.button.element_right.x",       "368"                   },
-  { "gfx.editor.button.element_right.y",       "48"                    },
-  { "gfx.editor.button.element_right.width",   "16"                    },
-  { "gfx.editor.button.element_right.height",  "16"                    },
-  { "gfx.editor.button.element_right.pressed_xoffset", "0"             },
-
-  { "gfx.editor.button.palette",               UNDEFINED_FILENAME      },
-
-  { "editor.no_toolbox_button",                        "RocksDoor.png"         },
-  { "editor.no_toolbox_button.x",              "506"                   },
-  { "editor.no_toolbox_button.y",              "286"                   },
-  { "editor.no_toolbox_button.width",          "22"                    },
-  { "editor.no_toolbox_button.height",         "22"                    },
-
-  { "gfx.editor.button.draw_single",           "RocksDoor.png"         },
-  { "gfx.editor.button.draw_single.x",         "706"                   },
-  { "gfx.editor.button.draw_single.y",         "242"                   },
-  { "gfx.editor.button.draw_single.width",     "22"                    },
-  { "gfx.editor.button.draw_single.height",    "22"                    },
-  { "gfx.editor.button.draw_single.pressed_xoffset", "-100"            },
-  { "gfx.editor.button.draw_single.active_yoffset",  "-94"             },
-
-  { "gfx.editor.button.draw_connected",                "RocksDoor.png"         },
-  { "gfx.editor.button.draw_connected.x",      "728"                   },
-  { "gfx.editor.button.draw_connected.y",      "242"                   },
-  { "gfx.editor.button.draw_connected.width",  "22"                    },
-  { "gfx.editor.button.draw_connected.height", "22"                    },
-  { "gfx.editor.button.draw_connected.pressed_xoffset", "-100"         },
-  { "gfx.editor.button.draw_connected.active_yoffset",  "-94"          },
-
-  { "gfx.editor.button.draw_line",             "RocksDoor.png"         },
-  { "gfx.editor.button.draw_line.x",           "750"                   },
-  { "gfx.editor.button.draw_line.y",           "242"                   },
-  { "gfx.editor.button.draw_line.width",       "22"                    },
-  { "gfx.editor.button.draw_line.height",      "22"                    },
-  { "gfx.editor.button.draw_line.pressed_xoffset", "-100"              },
-  { "gfx.editor.button.draw_line.active_yoffset",  "-94"               },
-
-  { "gfx.editor.button.draw_arc",              "RocksDoor.png"         },
-  { "gfx.editor.button.draw_arc.x",            "772"                   },
-  { "gfx.editor.button.draw_arc.y",            "242"                   },
-  { "gfx.editor.button.draw_arc.width",                "22"                    },
-  { "gfx.editor.button.draw_arc.height",       "22"                    },
-  { "gfx.editor.button.draw_arc.pressed_xoffset", "-100"               },
-  { "gfx.editor.button.draw_arc.active_yoffset",  "-94"                        },
-
-  { "gfx.editor.button.draw_rectangle",                "RocksDoor.png"         },
-  { "gfx.editor.button.draw_rectangle.x",      "706"                   },
-  { "gfx.editor.button.draw_rectangle.y",      "264"                   },
-  { "gfx.editor.button.draw_rectangle.width",  "22"                    },
-  { "gfx.editor.button.draw_rectangle.height", "22"                    },
-  { "gfx.editor.button.draw_rectangle.pressed_xoffset", "-100"         },
-  { "gfx.editor.button.draw_rectangle.active_yoffset",  "-94"          },
-
-  { "gfx.editor.button.draw_filled_box",       "RocksDoor.png"         },
-  { "gfx.editor.button.draw_filled_box.x",     "728"                   },
-  { "gfx.editor.button.draw_filled_box.y",     "264"                   },
-  { "gfx.editor.button.draw_filled_box.width", "22"                    },
-  { "gfx.editor.button.draw_filled_box.height",        "22"                    },
-  { "gfx.editor.button.draw_filled_box.pressed_xoffset", "-100"                },
-  { "gfx.editor.button.draw_filled_box.active_yoffset",  "-94"         },
-
-  { "gfx.editor.button.rotate_up",             "RocksDoor.png"         },
-  { "gfx.editor.button.rotate_up.x",           "750"                   },
-  { "gfx.editor.button.rotate_up.y",           "264"                   },
-  { "gfx.editor.button.rotate_up.width",       "22"                    },
-  { "gfx.editor.button.rotate_up.height",      "22"                    },
-  { "gfx.editor.button.rotate_up.pressed_xoffset", "-100"              },
-  { "gfx.editor.button.rotate_up.active_yoffset",  "-94"               },
-
-  { "gfx.editor.button.draw_text",             "RocksDoor.png"         },
-  { "gfx.editor.button.draw_text.x",           "772"                   },
-  { "gfx.editor.button.draw_text.y",           "264"                   },
-  { "gfx.editor.button.draw_text.width",       "22"                    },
-  { "gfx.editor.button.draw_text.height",      "22"                    },
-  { "gfx.editor.button.draw_text.pressed_xoffset", "-100"              },
-  { "gfx.editor.button.draw_text.active_yoffset",  "-94"               },
-
-  { "gfx.editor.button.flood_fill",            "RocksDoor.png"         },
-  { "gfx.editor.button.flood_fill.x",          "706"                   },
-  { "gfx.editor.button.flood_fill.y",          "286"                   },
-  { "gfx.editor.button.flood_fill.width",      "22"                    },
-  { "gfx.editor.button.flood_fill.height",     "22"                    },
-  { "gfx.editor.button.flood_fill.pressed_xoffset", "-100"             },
-  { "gfx.editor.button.flood_fill.active_yoffset",  "-94"              },
-
-  { "gfx.editor.button.rotate_left",           "RocksDoor.png"         },
-  { "gfx.editor.button.rotate_left.x",         "728"                   },
-  { "gfx.editor.button.rotate_left.y",         "286"                   },
-  { "gfx.editor.button.rotate_left.width",     "22"                    },
-  { "gfx.editor.button.rotate_left.height",    "22"                    },
-  { "gfx.editor.button.rotate_left.pressed_xoffset", "-100"            },
-  { "gfx.editor.button.rotate_left.active_yoffset",  "-94"             },
-
-  { "gfx.editor.button.zoom_level",            "RocksDoor2.png"        },
-  { "gfx.editor.button.zoom_level.x",          "350"                   },
-  { "gfx.editor.button.zoom_level.y",          "22"                    },
-  { "gfx.editor.button.zoom_level.width",      "22"                    },
-  { "gfx.editor.button.zoom_level.height",     "22"                    },
-  { "gfx.editor.button.zoom_level.pressed_xoffset", "-100"             },
-  { "gfx.editor.button.zoom_level.active_yoffset",  "-22"              },
-
-  { "gfx.editor.button.rotate_right",          "RocksDoor.png"         },
-  { "gfx.editor.button.rotate_right.x",                "772"                   },
-  { "gfx.editor.button.rotate_right.y",                "286"                   },
-  { "gfx.editor.button.rotate_right.width",    "22"                    },
-  { "gfx.editor.button.rotate_right.height",   "22"                    },
-  { "gfx.editor.button.rotate_right.pressed_xoffset", "-100"           },
-  { "gfx.editor.button.rotate_right.active_yoffset",  "-94"            },
-
-  { "gfx.editor.button.draw_random",           "RocksDoor.png"         },
-  { "gfx.editor.button.draw_random.x",         "706"                   },
-  { "gfx.editor.button.draw_random.y",         "308"                   },
-  { "gfx.editor.button.draw_random.width",     "22"                    },
-  { "gfx.editor.button.draw_random.height",    "22"                    },
-  { "gfx.editor.button.draw_random.pressed_xoffset", "-100"            },
-  { "gfx.editor.button.draw_random.active_yoffset",  "-94"             },
-
-  { "gfx.editor.button.grab_brush",            "RocksDoor.png"         },
-  { "gfx.editor.button.grab_brush.x",          "728"                   },
-  { "gfx.editor.button.grab_brush.y",          "308"                   },
-  { "gfx.editor.button.grab_brush.width",      "22"                    },
-  { "gfx.editor.button.grab_brush.height",     "22"                    },
-  { "gfx.editor.button.grab_brush.pressed_xoffset", "-100"             },
-  { "gfx.editor.button.grab_brush.active_yoffset",  "-94"              },
-
-  { "gfx.editor.button.rotate_down",           "RocksDoor.png"         },
-  { "gfx.editor.button.rotate_down.x",         "750"                   },
-  { "gfx.editor.button.rotate_down.y",         "308"                   },
-  { "gfx.editor.button.rotate_down.width",     "22"                    },
-  { "gfx.editor.button.rotate_down.height",    "22"                    },
-  { "gfx.editor.button.rotate_down.pressed_xoffset", "-100"            },
-  { "gfx.editor.button.rotate_down.active_yoffset",  "-94"             },
-
-  { "gfx.editor.button.pick_element",          "RocksDoor.png"         },
-  { "gfx.editor.button.pick_element.x",                "772"                   },
-  { "gfx.editor.button.pick_element.y",                "308"                   },
-  { "gfx.editor.button.pick_element.width",    "22"                    },
-  { "gfx.editor.button.pick_element.height",   "22"                    },
-  { "gfx.editor.button.pick_element.pressed_xoffset", "-100"           },
-  { "gfx.editor.button.pick_element.active_yoffset",  "-94"            },
-
-  { "gfx.editor.button.ce_copy_from",          "RocksDoor.png"         },
-  { "gfx.editor.button.ce_copy_from.x",                "528"                   },
-  { "gfx.editor.button.ce_copy_from.y",                "330"                   },
-  { "gfx.editor.button.ce_copy_from.width",    "22"                    },
-  { "gfx.editor.button.ce_copy_from.height",   "22"                    },
-  { "gfx.editor.button.ce_copy_from.pressed_xoffset", "-100"           },
-  { "gfx.editor.button.ce_copy_from.active_yoffset",  "-22"            },
-
-  { "gfx.editor.button.ce_copy_to",            "RocksDoor.png"         },
-  { "gfx.editor.button.ce_copy_to.x",          "550"                   },
-  { "gfx.editor.button.ce_copy_to.y",          "330"                   },
-  { "gfx.editor.button.ce_copy_to.width",      "22"                    },
-  { "gfx.editor.button.ce_copy_to.height",     "22"                    },
-  { "gfx.editor.button.ce_copy_to.pressed_xoffset", "-100"             },
-  { "gfx.editor.button.ce_copy_to.active_yoffset",  "-22"              },
-
-  { "gfx.editor.button.ce_swap",               "RocksDoor.png"         },
-  { "gfx.editor.button.ce_swap.x",             "572"                   },
-  { "gfx.editor.button.ce_swap.y",             "330"                   },
-  { "gfx.editor.button.ce_swap.width",         "22"                    },
-  { "gfx.editor.button.ce_swap.height",                "22"                    },
-  { "gfx.editor.button.ce_swap.pressed_xoffset", "-100"                        },
-  { "gfx.editor.button.ce_swap.active_yoffset",  "-22"                 },
-
-  { "gfx.editor.button.ce_copy",               "RocksDoor.png"         },
-  { "gfx.editor.button.ce_copy.x",             "550"                   },
-  { "gfx.editor.button.ce_copy.y",             "286"                   },
-  { "gfx.editor.button.ce_copy.width",         "22"                    },
-  { "gfx.editor.button.ce_copy.height",                "22"                    },
-  { "gfx.editor.button.ce_copy.pressed_xoffset", "-100"                        },
-
-  { "gfx.editor.button.ce_paste",              "RocksDoor.png"         },
-  { "gfx.editor.button.ce_paste.x",            "572"                   },
-  { "gfx.editor.button.ce_paste.y",            "286"                   },
-  { "gfx.editor.button.ce_paste.width",                "22"                    },
-  { "gfx.editor.button.ce_paste.height",       "22"                    },
-  { "gfx.editor.button.ce_paste.pressed_xoffset", "-100"               },
-
-  { "gfx.editor.button.cp_copy",               "RocksDoor.png"         },
-  { "gfx.editor.button.cp_copy.x",             "525"                   },
-  { "gfx.editor.button.cp_copy.y",             "50"                    },
-  { "gfx.editor.button.cp_copy.width",         "20"                    },
-  { "gfx.editor.button.cp_copy.height",                "20"                    },
-  { "gfx.editor.button.cp_copy.pressed_xoffset", "-20"                 },
-
-  { "gfx.editor.button.cp_paste",              "RocksDoor.png"         },
-  { "gfx.editor.button.cp_paste.x",            "525"                   },
-  { "gfx.editor.button.cp_paste.y",            "70"                    },
-  { "gfx.editor.button.cp_paste.width",                "20"                    },
-  { "gfx.editor.button.cp_paste.height",       "20"                    },
-  { "gfx.editor.button.cp_paste.pressed_xoffset", "-20"                        },
-
-  { "gfx.editor.button.undo",                  "RocksDoor.png"         },
-  { "gfx.editor.button.undo.x",                        "705"                   },
-  { "gfx.editor.button.undo.y",                        "335"                   },
-  { "gfx.editor.button.undo.width",            "30"                    },
-  { "gfx.editor.button.undo.height",           "20"                    },
-  { "gfx.editor.button.undo.pressed_xoffset",  "-100"                  },
-
-  { "gfx.editor.button.conf",                  "RocksDoor.png"         },
-  { "gfx.editor.button.conf.x",                        "735"                   },
-  { "gfx.editor.button.conf.y",                        "335"                   },
-  { "gfx.editor.button.conf.width",            "30"                    },
-  { "gfx.editor.button.conf.height",           "20"                    },
-  { "gfx.editor.button.conf.pressed_xoffset",  "-100"                  },
-
-  { "gfx.editor.button.save",                  "RocksDoor.png"         },
-  { "gfx.editor.button.save.x",                        "765"                   },
-  { "gfx.editor.button.save.y",                        "335"                   },
-  { "gfx.editor.button.save.width",            "30"                    },
-  { "gfx.editor.button.save.height",           "20"                    },
-  { "gfx.editor.button.save.pressed_xoffset",  "-100"                  },
-
-  { "gfx.editor.button.clear",                 "RocksDoor.png"         },
-  { "gfx.editor.button.clear.x",               "705"                   },
-  { "gfx.editor.button.clear.y",               "355"                   },
-  { "gfx.editor.button.clear.width",           "30"                    },
-  { "gfx.editor.button.clear.height",          "20"                    },
-  { "gfx.editor.button.clear.pressed_xoffset", "-100"                  },
-
-  { "gfx.editor.button.test",                  "RocksDoor.png"         },
-  { "gfx.editor.button.test.x",                        "735"                   },
-  { "gfx.editor.button.test.y",                        "355"                   },
-  { "gfx.editor.button.test.width",            "30"                    },
-  { "gfx.editor.button.test.height",           "20"                    },
-  { "gfx.editor.button.test.pressed_xoffset",  "-100"                  },
-
-  { "gfx.editor.button.exit",                  "RocksDoor.png"         },
-  { "gfx.editor.button.exit.x",                        "765"                   },
-  { "gfx.editor.button.exit.y",                        "355"                   },
-  { "gfx.editor.button.exit.width",            "30"                    },
-  { "gfx.editor.button.exit.height",           "20"                    },
-  { "gfx.editor.button.exit.pressed_xoffset",  "-100"                  },
-
-  { "gfx.editor.input.level_number",           "RocksDoor.png"         },
-  { "gfx.editor.input.level_number.x",         "529"                   },
-  { "gfx.editor.input.level_number.y",         "5"                     },
-  { "gfx.editor.input.level_number.width",     "42"                    },
-  { "gfx.editor.input.level_number.height",    "16"                    },
-  { "gfx.editor.input.level_number.border_size","1"                    },
-
-  { "setup.input.text",                                "RocksSP.png"           },
-  { "setup.input.text.x",                      "0"                     },
-  { "setup.input.text.y",                      "0"                     },
-  { "setup.input.text.width",                  "32"                    },
-  { "setup.input.text.height",                 "32"                    },
-  { "setup.input.text.active_xoffset",         "0"                     },
-  { "setup.input.text.border_size",            "0"                     },
-
-  { "global.border",                           "RocksScreen.png"       },
-  { "global.border.MAIN",                      UNDEFINED_FILENAME      },
-  { "global.border.SCORES",                    UNDEFINED_FILENAME      },
-  { "global.border.EDITOR",                    UNDEFINED_FILENAME      },
-  { "global.border.PLAYING",                   UNDEFINED_FILENAME      },
-
-  { "global.door",                             "RocksDoor.png"         },
-
-  { "global.busy",                             "RocksBusy.png"         },
-  { "global.busy.x",                           "0"                     },
-  { "global.busy.y",                           "0"                     },
-  { "global.busy.width",                       "32"                    },
-  { "global.busy.height",                      "32"                    },
-  { "global.busy.frames",                      "28"                    },
-  { "global.busy.frames_per_line",             "7"                     },
-  { "global.busy.delay",                       "2"                     },
-
-  { "global.tile_cursor",                      "RocksMore.png"         },
-  { "global.tile_cursor.xpos",                 "10"                    },
-  { "global.tile_cursor.ypos",                 "7"                     },
-  { "global.tile_cursor.frames",               "1"                     },
-
-  { "background",                              UNDEFINED_FILENAME      },
-  { "background.TITLE_INITIAL",                        UNDEFINED_FILENAME      },
-  { "background.TITLE",                                UNDEFINED_FILENAME      },
-  { "background.MAIN",                         UNDEFINED_FILENAME      },
-  { "background.NAMES",                                UNDEFINED_FILENAME      },
-  { "background.LEVELS",                       UNDEFINED_FILENAME      },
-  { "background.LEVELNR",                      UNDEFINED_FILENAME      },
-  { "background.SCORES",                       UNDEFINED_FILENAME      },
-  { "background.EDITOR",                       UNDEFINED_FILENAME      },
-  { "background.INFO",                         UNDEFINED_FILENAME      },
-  { "background.INFO[ELEMENTS]",               UNDEFINED_FILENAME      },
-  { "background.INFO[MUSIC]",                  UNDEFINED_FILENAME      },
-  { "background.INFO[CREDITS]",                        UNDEFINED_FILENAME      },
-  { "background.INFO[PROGRAM]",                        UNDEFINED_FILENAME      },
-  { "background.INFO[VERSION]",                        UNDEFINED_FILENAME      },
-  { "background.INFO[LEVELSET]",               UNDEFINED_FILENAME      },
-  { "background.SETUP",                                UNDEFINED_FILENAME      },
-  { "background.PLAYING",                      UNDEFINED_FILENAME      },
-  { "background.DOOR",                         UNDEFINED_FILENAME      },
-  { "background.TAPE",                         "RocksDoor.png"         },
-  { "background.TAPE.x",                       "200"                   },
-  { "background.TAPE.y",                       "280"                   },
-  { "background.TAPE.width",                   "100"                   },
-  { "background.TAPE.height",                  "100"                   },
-  { "background.PANEL",                                "RocksDoor.png"         },
-  { "background.PANEL.x",                      "400"                   },
-  { "background.PANEL.y",                      "0"                     },
-  { "background.PANEL.width",                  "100"                   },
-  { "background.PANEL.height",                 "280"                   },
-  { "background.PALETTE",                      "RocksDoor.png"         },
-  { "background.PALETTE.x",                    "500"                   },
-  { "background.PALETTE.y",                    "0"                     },
-  { "background.PALETTE.width",                        "100"                   },
-  { "background.PALETTE.height",               "280"                   },
-  { "background.TOOLBOX",                      "RocksDoor.png"         },
-  { "background.TOOLBOX.x",                    "700"                   },
-  { "background.TOOLBOX.y",                    "236"                   },
-  { "background.TOOLBOX.width",                        "100"                   },
-  { "background.TOOLBOX.height",               "144"                   },
-
-  { "background.titlescreen_initial_1",                UNDEFINED_FILENAME      },
-  { "background.titlescreen_initial_2",                UNDEFINED_FILENAME      },
-  { "background.titlescreen_initial_3",                UNDEFINED_FILENAME      },
-  { "background.titlescreen_initial_4",                UNDEFINED_FILENAME      },
-  { "background.titlescreen_initial_5",                UNDEFINED_FILENAME      },
-  { "background.titlescreen_1",                        UNDEFINED_FILENAME      },
-  { "background.titlescreen_2",                        UNDEFINED_FILENAME      },
-  { "background.titlescreen_3",                        UNDEFINED_FILENAME      },
-  { "background.titlescreen_4",                        UNDEFINED_FILENAME      },
-  { "background.titlescreen_5",                        UNDEFINED_FILENAME      },
-  { "background.titlemessage_initial_1",       UNDEFINED_FILENAME      },
-  { "background.titlemessage_initial_2",       UNDEFINED_FILENAME      },
-  { "background.titlemessage_initial_3",       UNDEFINED_FILENAME      },
-  { "background.titlemessage_initial_4",       UNDEFINED_FILENAME      },
-  { "background.titlemessage_initial_5",       UNDEFINED_FILENAME      },
-  { "background.titlemessage_1",               UNDEFINED_FILENAME      },
-  { "background.titlemessage_2",               UNDEFINED_FILENAME      },
-  { "background.titlemessage_3",               UNDEFINED_FILENAME      },
-  { "background.titlemessage_4",               UNDEFINED_FILENAME      },
-  { "background.titlemessage_5",               UNDEFINED_FILENAME      },
-
-  { "background.envelope_1",                   "RocksScreen.png"       },
-  { "background.envelope_1.x",                 "0"                     },
-  { "background.envelope_1.y",                 "0"                     },
-  { "background.envelope_1.width",             "560"                   },
-  { "background.envelope_1.height",            "560"                   },
-  { "background.envelope_1.anim_mode",         "default"               },
-  { "background.envelope_1.draw_masked",       "false"                 },
-  { "background.envelope_2",                   "RocksScreen.png"       },
-  { "background.envelope_2.x",                 "0"                     },
-  { "background.envelope_2.y",                 "0"                     },
-  { "background.envelope_2.width",             "560"                   },
-  { "background.envelope_2.height",            "560"                   },
-  { "background.envelope_2.anim_mode",         "default"               },
-  { "background.envelope_2.draw_masked",       "false"                 },
-  { "background.envelope_3",                   "RocksScreen.png"       },
-  { "background.envelope_3.x",                 "0"                     },
-  { "background.envelope_3.y",                 "0"                     },
-  { "background.envelope_3.width",             "560"                   },
-  { "background.envelope_3.height",            "560"                   },
-  { "background.envelope_3.anim_mode",         "default"               },
-  { "background.envelope_3.draw_masked",       "false"                 },
-  { "background.envelope_4",                   "RocksScreen.png"       },
-  { "background.envelope_4.x",                 "0"                     },
-  { "background.envelope_4.y",                 "0"                     },
-  { "background.envelope_4.width",             "560"                   },
-  { "background.envelope_4.height",            "560"                   },
-  { "background.envelope_4.anim_mode",         "default"               },
-  { "background.envelope_4.draw_masked",       "false"                 },
-
-  { "background.request",                      "RocksScreen.png"       },
-  { "background.request.x",                    "562"                   },
-  { "background.request.y",                    "56"                    },
-  { "background.request.width",                        "108"                   },
-  { "background.request.height",               "288"                   },
-  { "background.request.anim_mode",            "default"               },
-  { "background.request.draw_masked",          "false"                 },
-
-  { "titlescreen_initial_1",                   UNDEFINED_FILENAME      },
-  { "titlescreen_initial_2",                   UNDEFINED_FILENAME      },
-  { "titlescreen_initial_3",                   UNDEFINED_FILENAME      },
-  { "titlescreen_initial_4",                   UNDEFINED_FILENAME      },
-  { "titlescreen_initial_5",                   UNDEFINED_FILENAME      },
-  { "titlescreen_1",                           UNDEFINED_FILENAME      },
-  { "titlescreen_2",                           UNDEFINED_FILENAME      },
-  { "titlescreen_3",                           UNDEFINED_FILENAME      },
-  { "titlescreen_4",                           UNDEFINED_FILENAME      },
-  { "titlescreen_5",                           UNDEFINED_FILENAME      },
-
-  { "gfx.door_1.part_1",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_1.x",                     "0"                     },
-  { "gfx.door_1.part_1.y",                     "0"                     },
-  { "gfx.door_1.part_1.width",                 "100"                   },
-  { "gfx.door_1.part_1.height",                        "77"                    },
-  { "gfx.door_1.part_1.frames",                        "1"                     },
-  { "gfx.door_1.part_2",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_2.x",                     "0"                     },
-  { "gfx.door_1.part_2.y",                     "77"                    },
-  { "gfx.door_1.part_2.width",                 "100"                   },
-  { "gfx.door_1.part_2.height",                        "63"                    },
-  { "gfx.door_1.part_2.frames",                        "1"                     },
-  { "gfx.door_1.part_3",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_3.x",                     "0"                     },
-  { "gfx.door_1.part_3.y",                     "140"                   },
-  { "gfx.door_1.part_3.width",                 "100"                   },
-  { "gfx.door_1.part_3.height",                        "63"                    },
-  { "gfx.door_1.part_3.frames",                        "1"                     },
-  { "gfx.door_1.part_4",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_4.x",                     "0"                     },
-  { "gfx.door_1.part_4.y",                     "203"                   },
-  { "gfx.door_1.part_4.width",                 "100"                   },
-  { "gfx.door_1.part_4.height",                        "77"                    },
-  { "gfx.door_1.part_4.frames",                        "1"                     },
-  { "gfx.door_1.part_5",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_5.x",                     "100"                   },
-  { "gfx.door_1.part_5.y",                     "0"                     },
-  { "gfx.door_1.part_5.width",                 "100"                   },
-  { "gfx.door_1.part_5.height",                        "77"                    },
-  { "gfx.door_1.part_5.frames",                        "1"                     },
-  { "gfx.door_1.part_6",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_6.x",                     "100"                   },
-  { "gfx.door_1.part_6.y",                     "77"                    },
-  { "gfx.door_1.part_6.width",                 "100"                   },
-  { "gfx.door_1.part_6.height",                        "63"                    },
-  { "gfx.door_1.part_6.frames",                        "1"                     },
-  { "gfx.door_1.part_7",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_7.x",                     "100"                   },
-  { "gfx.door_1.part_7.y",                     "140"                   },
-  { "gfx.door_1.part_7.width",                 "100"                   },
-  { "gfx.door_1.part_7.height",                        "63"                    },
-  { "gfx.door_1.part_7.frames",                        "1"                     },
-  { "gfx.door_1.part_8",                       "RocksDoor.png"         },
-  { "gfx.door_1.part_8.x",                     "100"                   },
-  { "gfx.door_1.part_8.y",                     "203"                   },
-  { "gfx.door_1.part_8.width",                 "100"                   },
-  { "gfx.door_1.part_8.height",                        "77"                    },
-  { "gfx.door_1.part_8.frames",                        "1"                     },
-
-  { "gfx.door_2.part_1",                       "RocksDoor.png"         },
-  { "gfx.door_2.part_1.x",                     "0"                     },
-  { "gfx.door_2.part_1.y",                     "280"                   },
-  { "gfx.door_2.part_1.width",                 "100"                   },
-  { "gfx.door_2.part_1.height",                        "50"                    },
-  { "gfx.door_2.part_1.frames",                        "1"                     },
-  { "gfx.door_2.part_2",                       "RocksDoor.png"         },
-  { "gfx.door_2.part_2.x",                     "0"                     },
-  { "gfx.door_2.part_2.y",                     "330"                   },
-  { "gfx.door_2.part_2.width",                 "100"                   },
-  { "gfx.door_2.part_2.height",                        "50"                    },
-  { "gfx.door_2.part_2.frames",                        "1"                     },
-  { "gfx.door_2.part_3",                       "RocksDoor.png"         },
-  { "gfx.door_2.part_3.x",                     "100"                   },
-  { "gfx.door_2.part_3.y",                     "280"                   },
-  { "gfx.door_2.part_3.width",                 "100"                   },
-  { "gfx.door_2.part_3.height",                        "50"                    },
-  { "gfx.door_2.part_3.frames",                        "1"                     },
-  { "gfx.door_2.part_4",                       "RocksDoor.png"         },
-  { "gfx.door_2.part_4.x",                     "100"                   },
-  { "gfx.door_2.part_4.y",                     "330"                   },
-  { "gfx.door_2.part_4.width",                 "100"                   },
-  { "gfx.door_2.part_4.height",                        "50"                    },
-  { "gfx.door_2.part_4.frames",                        "1"                     },
-  { "gfx.door_2.part_5",                       UNDEFINED_FILENAME      },
-  { "gfx.door_2.part_6",                       UNDEFINED_FILENAME      },
-  { "gfx.door_2.part_7",                       UNDEFINED_FILENAME      },
-  { "gfx.door_2.part_8",                       UNDEFINED_FILENAME      },
-
-  { "door_2.top_border_correction",            "RocksDoor.png"         },
-  { "door_2.top_border_correction.x",          "600"                   },
-  { "door_2.top_border_correction.y",          "0"                     },
-  { "door_2.top_border_correction.width",      "108"                   },
-  { "door_2.top_border_correction.height",     "8"                     },
+  { "sp_frame_horizontal",                             "RocksSP.png"                   },
+  { "sp_frame_horizontal.xpos",                                "7"                             },
+  { "sp_frame_horizontal.ypos",                                "14"                            },
+  { "sp_frame_vertical",                               "RocksSP.png"                   },
+  { "sp_frame_vertical.xpos",                          "6"                             },
+  { "sp_frame_vertical.ypos",                          "14"                            },
+  { "sp_frame_corner",                                 "RocksSP.png"                   },
+  { "sp_frame_corner.xpos",                            "5"                             },
+  { "sp_frame_corner.ypos",                            "14"                            },
+
+  { "toon_1",                                          "RocksToons.png"                },
+  { "toon_1.x",                                                "2"                             },
+  { "toon_1.y",                                                "72"                            },
+  { "toon_1.width",                                    "40"                            },
+  { "toon_1.height",                                   "48"                            },
+  { "toon_1.frames",                                   "8"                             },
+  { "toon_1.delay",                                    "1"                             },
+  { "toon_1.step_offset",                              "4"                             },
+  { "toon_1.step_delay",                               "5"                             },
+  { "toon_1.direction",                                        "right"                         },
+  { "toon_1.position",                                 "bottom"                        },
+
+  { "toon_2",                                          "RocksToons.png"                },
+  { "toon_2.x",                                                "2"                             },
+  { "toon_2.y",                                                "186"                           },
+  { "toon_2.width",                                    "40"                            },
+  { "toon_2.height",                                   "48"                            },
+  { "toon_2.frames",                                   "8"                             },
+  { "toon_2.delay",                                    "1"                             },
+  { "toon_2.step_offset",                              "4"                             },
+  { "toon_2.step_delay",                               "5"                             },
+  { "toon_2.direction",                                        "left"                          },
+  { "toon_2.position",                                 "bottom"                        },
+
+  { "toon_3",                                          "RocksToons.png"                },
+  { "toon_3.x",                                                "2"                             },
+  { "toon_3.y",                                                "125"                           },
+  { "toon_3.width",                                    "48"                            },
+  { "toon_3.height",                                   "56"                            },
+  { "toon_3.frames",                                   "8"                             },
+  { "toon_3.delay",                                    "1"                             },
+  { "toon_3.step_offset",                              "4"                             },
+  { "toon_3.step_delay",                               "5"                             },
+  { "toon_3.direction",                                        "right"                         },
+  { "toon_3.position",                                 "bottom"                        },
+
+  { "toon_4",                                          "RocksToons.png"                },
+  { "toon_4.x",                                                "327"                           },
+  { "toon_4.y",                                                "10"                            },
+  { "toon_4.width",                                    "80"                            },
+  { "toon_4.height",                                   "110"                           },
+  { "toon_4.frames",                                   "1"                             },
+  { "toon_4.delay",                                    "1"                             },
+  { "toon_4.step_offset",                              "1"                             },
+  { "toon_4.step_delay",                               "1"                             },
+  { "toon_4.direction",                                        "up"                            },
+  { "toon_4.position",                                 "any"                           },
+
+  { "toon_5",                                          "RocksToons.png"                },
+  { "toon_5.x",                                                "2"                             },
+  { "toon_5.y",                                                "2"                             },
+  { "toon_5.width",                                    "32"                            },
+  { "toon_5.height",                                   "30"                            },
+  { "toon_5.frames",                                   "8"                             },
+  { "toon_5.delay",                                    "2"                             },
+  { "toon_5.anim_mode",                                        "pingpong2"                     },
+  { "toon_5.step_offset",                              "2"                             },
+  { "toon_5.step_delay",                               "1"                             },
+  { "toon_5.direction",                                        "right"                         },
+  { "toon_5.position",                                 "upper"                         },
+
+  { "toon_6",                                          "RocksToons.png"                },
+  { "toon_6.x",                                                "2"                             },
+  { "toon_6.y",                                                "37"                            },
+  { "toon_6.width",                                    "32"                            },
+  { "toon_6.height",                                   "30"                            },
+  { "toon_6.frames",                                   "8"                             },
+  { "toon_6.delay",                                    "2"                             },
+  { "toon_6.anim_mode",                                        "pingpong2"                     },
+  { "toon_6.step_offset",                              "2"                             },
+  { "toon_6.step_delay",                               "1"                             },
+  { "toon_6.direction",                                        "left"                          },
+  { "toon_6.position",                                 "upper"                         },
+
+  { "toon_7",                                          "RocksMore.png"                 },
+  { "toon_7.xpos",                                     "0"                             },
+  { "toon_7.ypos",                                     "6"                             },
+  { "toon_7.frames",                                   "16"                            },
+  { "toon_7.delay",                                    "2"                             },
+  { "toon_7.direction",                                        "down"                          },
+  { "toon_7.position",                                 "any"                           },
+
+  { "toon_8",                                          "RocksHeroes.png"               },
+  { "toon_8.xpos",                                     "4"                             },
+  { "toon_8.ypos",                                     "1"                             },
+  { "toon_8.frames",                                   "4"                             },
+  { "toon_8.delay",                                    "4"                             },
+  { "toon_8.direction",                                        "right"                         },
+  { "toon_8.position",                                 "bottom"                        },
+
+  { "toon_9",                                          "RocksHeroes.png"               },
+  { "toon_9.xpos",                                     "8"                             },
+  { "toon_9.ypos",                                     "7"                             },
+  { "toon_9.frames",                                   "4"                             },
+  { "toon_9.delay",                                    "2"                             },
+  { "toon_9.direction",                                        "left"                          },
+  { "toon_9.position",                                 "bottom"                        },
+
+  { "toon_10",                                         "RocksHeroes.png"               },
+  { "toon_10.xpos",                                    "12"                            },
+  { "toon_10.ypos",                                    "7"                             },
+  { "toon_10.frames",                                  "4"                             },
+  { "toon_10.delay",                                   "2"                             },
+  { "toon_10.direction",                               "right"                         },
+  { "toon_10.position",                                        "bottom"                        },
+
+  { "toon_11",                                         "RocksHeroes.png"               },
+  { "toon_11.xpos",                                    "8"                             },
+  { "toon_11.ypos",                                    "5"                             },
+  { "toon_11.frames",                                  "4"                             },
+  { "toon_11.delay",                                   "2"                             },
+  { "toon_11.direction",                               "left"                          },
+  { "toon_11.position",                                        "bottom"                        },
+
+  { "toon_12",                                         "RocksHeroes.png"               },
+  { "toon_12.xpos",                                    "12"                            },
+  { "toon_12.ypos",                                    "5"                             },
+  { "toon_12.frames",                                  "4"                             },
+  { "toon_12.delay",                                   "2"                             },
+  { "toon_12.direction",                               "right"                         },
+  { "toon_12.position",                                        "bottom"                        },
+
+  { "toon_13",                                         "RocksHeroes.png"               },
+  { "toon_13.xpos",                                    "8"                             },
+  { "toon_13.ypos",                                    "1"                             },
+  { "toon_13.frames",                                  "4"                             },
+  { "toon_13.delay",                                   "2"                             },
+  { "toon_13.direction",                               "left"                          },
+  { "toon_13.position",                                        "bottom"                        },
+
+  { "toon_14",                                         "RocksHeroes.png"               },
+  { "toon_14.xpos",                                    "12"                            },
+  { "toon_14.ypos",                                    "1"                             },
+  { "toon_14.frames",                                  "4"                             },
+  { "toon_14.delay",                                   "2"                             },
+  { "toon_14.direction",                               "right"                         },
+  { "toon_14.position",                                        "bottom"                        },
+
+  { "toon_15",                                         "RocksHeroes.png"               },
+  { "toon_15.xpos",                                    "8"                             },
+  { "toon_15.ypos",                                    "3"                             },
+  { "toon_15.frames",                                  "4"                             },
+  { "toon_15.delay",                                   "2"                             },
+  { "toon_15.direction",                               "left"                          },
+  { "toon_15.position",                                        "bottom"                        },
+
+  { "toon_16",                                         "RocksHeroes.png"               },
+  { "toon_16.xpos",                                    "12"                            },
+  { "toon_16.ypos",                                    "3"                             },
+  { "toon_16.frames",                                  "4"                             },
+  { "toon_16.delay",                                   "2"                             },
+  { "toon_16.direction",                               "right"                         },
+  { "toon_16.position",                                        "bottom"                        },
+
+  { "toon_17",                                         "RocksHeroes.png"               },
+  { "toon_17.xpos",                                    "8"                             },
+  { "toon_17.ypos",                                    "9"                             },
+  { "toon_17.frames",                                  "8"                             },
+  { "toon_17.delay",                                   "2"                             },
+  { "toon_17.direction",                               "left"                          },
+  { "toon_17.position",                                        "any"                           },
+
+  { "toon_18",                                         "RocksHeroes.png"               },
+  { "toon_18.xpos",                                    "8"                             },
+  { "toon_18.ypos",                                    "9"                             },
+  { "toon_18.frames",                                  "8"                             },
+  { "toon_18.delay",                                   "2"                             },
+  { "toon_18.direction",                               "right"                         },
+  { "toon_18.position",                                        "any"                           },
+
+  { "toon_19",                                         "RocksElements.png"             },
+  { "toon_19.xpos",                                    "8"                             },
+  { "toon_19.ypos",                                    "0"                             },
+  { "toon_19.frames",                                  "2"                             },
+  { "toon_19.delay",                                   "4"                             },
+  { "toon_19.direction",                               "down"                          },
+  { "toon_19.position",                                        "any"                           },
+
+  { "toon_20",                                         "RocksElements.png"             },
+  { "toon_20.xpos",                                    "10"                            },
+  { "toon_20.ypos",                                    "0"                             },
+  { "toon_20.frames",                                  "2"                             },
+  { "toon_20.delay",                                   "4"                             },
+  { "toon_20.direction",                               "down"                          },
+  { "toon_20.position",                                        "any"                           },
+
+  { "gfx.global.anim_1",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_2",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_3",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_4",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_5",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_6",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_7",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_8",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_9",                               UNDEFINED_FILENAME              },
+  { "gfx.global.anim_10",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_11",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_12",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_13",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_14",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_15",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_16",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_17",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_18",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_19",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_20",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_21",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_22",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_23",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_24",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_25",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_26",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_27",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_28",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_29",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_30",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_31",                              UNDEFINED_FILENAME              },
+  { "gfx.global.anim_32",                              UNDEFINED_FILENAME              },
+
+  { "global.anim_1",                                   UNDEFINED_FILENAME              },
+  { "global.anim_2",                                   UNDEFINED_FILENAME              },
+  { "global.anim_3",                                   UNDEFINED_FILENAME              },
+  { "global.anim_4",                                   UNDEFINED_FILENAME              },
+  { "global.anim_5",                                   UNDEFINED_FILENAME              },
+  { "global.anim_6",                                   UNDEFINED_FILENAME              },
+  { "global.anim_7",                                   UNDEFINED_FILENAME              },
+  { "global.anim_8",                                   UNDEFINED_FILENAME              },
+  { "global.anim_9",                                   UNDEFINED_FILENAME              },
+  { "global.anim_10",                                  UNDEFINED_FILENAME              },
+  { "global.anim_11",                                  UNDEFINED_FILENAME              },
+  { "global.anim_12",                                  UNDEFINED_FILENAME              },
+  { "global.anim_13",                                  UNDEFINED_FILENAME              },
+  { "global.anim_14",                                  UNDEFINED_FILENAME              },
+  { "global.anim_15",                                  UNDEFINED_FILENAME              },
+  { "global.anim_16",                                  UNDEFINED_FILENAME              },
+  { "global.anim_17",                                  UNDEFINED_FILENAME              },
+  { "global.anim_18",                                  UNDEFINED_FILENAME              },
+  { "global.anim_19",                                  UNDEFINED_FILENAME              },
+  { "global.anim_20",                                  UNDEFINED_FILENAME              },
+  { "global.anim_21",                                  UNDEFINED_FILENAME              },
+  { "global.anim_22",                                  UNDEFINED_FILENAME              },
+  { "global.anim_23",                                  UNDEFINED_FILENAME              },
+  { "global.anim_24",                                  UNDEFINED_FILENAME              },
+  { "global.anim_25",                                  UNDEFINED_FILENAME              },
+  { "global.anim_26",                                  UNDEFINED_FILENAME              },
+  { "global.anim_27",                                  UNDEFINED_FILENAME              },
+  { "global.anim_28",                                  UNDEFINED_FILENAME              },
+  { "global.anim_29",                                  UNDEFINED_FILENAME              },
+  { "global.anim_30",                                  UNDEFINED_FILENAME              },
+  { "global.anim_31",                                  UNDEFINED_FILENAME              },
+  { "global.anim_32",                                  UNDEFINED_FILENAME              },
+
+  { "internal.global.toon_default",                    UNDEFINED_FILENAME              },
+  { "internal.global.toon_default.anim_mode",          "random"                        },
+
+  { "internal.global.anim_default",                    UNDEFINED_FILENAME              },
+
+  { "menu.calibrate_red",                              "RocksElements.png"             },
+  { "menu.calibrate_red.xpos",                         "12"                            },
+  { "menu.calibrate_red.ypos",                         "8"                             },
+  { "menu.calibrate_red.frames",                       "1"                             },
+  { "menu.calibrate_blue",                             "RocksElements.png"             },
+  { "menu.calibrate_blue.xpos",                                "13"                            },
+  { "menu.calibrate_blue.ypos",                                "8"                             },
+  { "menu.calibrate_blue.frames",                      "1"                             },
+  { "menu.calibrate_yellow",                           "RocksElements.png"             },
+  { "menu.calibrate_yellow.xpos",                      "14"                            },
+  { "menu.calibrate_yellow.ypos",                      "8"                             },
+  { "menu.calibrate_yellow.frames",                    "1"                             },
+
+  { "menu.button",                                     "RocksElements.png"             },
+  { "menu.button.xpos",                                        "13"                            },
+  { "menu.button.ypos",                                        "8"                             },
+  { "menu.button.frames",                              "1"                             },
+  { "menu.button.active",                              "RocksElements.png"             },
+  { "menu.button.active.xpos",                         "12"                            },
+  { "menu.button.active.ypos",                         "8"                             },
+  { "menu.button.active.frames",                       "1"                             },
+
+  { "menu.button_left",                                        "RocksDC.png"                   },
+  { "menu.button_left.xpos",                           "8"                             },
+  { "menu.button_left.ypos",                           "8"                             },
+  { "menu.button_left.frames",                         "1"                             },
+  { "menu.button_left.active",                         "RocksDC.png"                   },
+  { "menu.button_left.active.xpos",                    "8"                             },
+  { "menu.button_left.active.ypos",                    "9"                             },
+  { "menu.button_left.active.frames",                  "1"                             },
+  { "menu.button_right",                               "RocksDC.png"                   },
+  { "menu.button_right.xpos",                          "9"                             },
+  { "menu.button_right.ypos",                          "8"                             },
+  { "menu.button_right.frames",                                "1"                             },
+  { "menu.button_right.active",                                "RocksDC.png"                   },
+  { "menu.button_right.active.xpos",                   "9"                             },
+  { "menu.button_right.active.ypos",                   "9"                             },
+  { "menu.button_right.active.frames",                 "1"                             },
+  { "menu.button_up",                                  "RocksDC.png"                   },
+  { "menu.button_up.xpos",                             "10"                            },
+  { "menu.button_up.ypos",                             "8"                             },
+  { "menu.button_up.frames",                           "1"                             },
+  { "menu.button_up.active",                           "RocksDC.png"                   },
+  { "menu.button_up.active.xpos",                      "10"                            },
+  { "menu.button_up.active.ypos",                      "9"                             },
+  { "menu.button_up.active.frames",                    "1"                             },
+  { "menu.button_down",                                        "RocksDC.png"                   },
+  { "menu.button_down.xpos",                           "11"                            },
+  { "menu.button_down.ypos",                           "8"                             },
+  { "menu.button_down.frames",                         "1"                             },
+  { "menu.button_down.active",                         "RocksDC.png"                   },
+  { "menu.button_down.active.xpos",                    "11"                            },
+  { "menu.button_down.active.ypos",                    "9"                             },
+  { "menu.button_down.active.frames",                  "1"                             },
+
+  { "menu.button_enter_menu",                          UNDEFINED_FILENAME              },
+  { "menu.button_enter_menu.clone_from",               "menu.button_right"             },
+  { "menu.button_enter_menu.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_enter_menu.active.clone_from",                "menu.button_right.active"      },
+  { "menu.button_leave_menu",                          UNDEFINED_FILENAME              },
+  { "menu.button_leave_menu.clone_from",               "menu.button_left"              },
+  { "menu.button_leave_menu.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_leave_menu.active.clone_from",                "menu.button_left.active"       },
+
+  { "menu.button_next_level",                          UNDEFINED_FILENAME              },
+  { "menu.button_next_level.clone_from",               "menu.button_right"             },
+  { "menu.button_next_level.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_next_level.active.clone_from",                "menu.button_right.active"      },
+  { "menu.button_prev_level",                          UNDEFINED_FILENAME              },
+  { "menu.button_prev_level.clone_from",               "menu.button_left"              },
+  { "menu.button_prev_level.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_prev_level.active.clone_from",                "menu.button_left.active"       },
+
+  { "menu.button_next_level2",                         UNDEFINED_FILENAME              },
+  { "menu.button_next_level2.clone_from",              "menu.button_right"             },
+  { "menu.button_next_level2.active",                  UNDEFINED_FILENAME              },
+  { "menu.button_next_level2.active.clone_from",       "menu.button_right.active"      },
+  { "menu.button_prev_level2",                         UNDEFINED_FILENAME              },
+  { "menu.button_prev_level2.clone_from",              "menu.button_left"              },
+  { "menu.button_prev_level2.active",                  UNDEFINED_FILENAME              },
+  { "menu.button_prev_level2.active.clone_from",       "menu.button_left.active"       },
+
+  { "menu.button_next_score",                          UNDEFINED_FILENAME              },
+  { "menu.button_next_score.clone_from",               "menu.button_down"              },
+  { "menu.button_next_score.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_next_score.active.clone_from",                "menu.button_down.active"       },
+  { "menu.button_prev_score",                          UNDEFINED_FILENAME              },
+  { "menu.button_prev_score.clone_from",               "menu.button_up"                },
+  { "menu.button_prev_score.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_prev_score.active.clone_from",                "menu.button_up.active"         },
+
+  { "menu.button_play_tape",                           UNDEFINED_FILENAME              },
+  { "menu.button_play_tape.clone_from",                        "gfx.tape.button.play"          },
+
+  { "menu.button_name",                                        UNDEFINED_FILENAME              },
+  { "menu.button_name.clone_from",                     "menu.button"                   },
+  { "menu.button_name.active",                         UNDEFINED_FILENAME              },
+  { "menu.button_name.active.clone_from",              "menu.button.active"            },
+  { "menu.button_levels",                              UNDEFINED_FILENAME              },
+  { "menu.button_levels.clone_from",                   "menu.button_right"             },
+  { "menu.button_levels.active",                       UNDEFINED_FILENAME              },
+  { "menu.button_levels.active.clone_from",            "menu.button_right.active"      },
+  { "menu.button_scores",                              UNDEFINED_FILENAME              },
+  { "menu.button_scores.clone_from",                   "menu.button"                   },
+  { "menu.button_scores.active",                       UNDEFINED_FILENAME              },
+  { "menu.button_scores.active.clone_from",            "menu.button.active"            },
+  { "menu.button_editor",                              UNDEFINED_FILENAME              },
+  { "menu.button_editor.clone_from",                   "menu.button"                   },
+  { "menu.button_editor.active",                       UNDEFINED_FILENAME              },
+  { "menu.button_editor.active.clone_from",            "menu.button.active"            },
+  { "menu.button_info",                                        UNDEFINED_FILENAME              },
+  { "menu.button_info.clone_from",                     "menu.button_right"             },
+  { "menu.button_info.active",                         UNDEFINED_FILENAME              },
+  { "menu.button_info.active.clone_from",              "menu.button_right.active"      },
+  { "menu.button_game",                                        UNDEFINED_FILENAME              },
+  { "menu.button_game.clone_from",                     "menu.button"                   },
+  { "menu.button_game.active",                         UNDEFINED_FILENAME              },
+  { "menu.button_game.active.clone_from",              "menu.button.active"            },
+  { "menu.button_setup",                               UNDEFINED_FILENAME              },
+  { "menu.button_setup.clone_from",                    "menu.button_right"             },
+  { "menu.button_setup.active",                                UNDEFINED_FILENAME              },
+  { "menu.button_setup.active.clone_from",             "menu.button_right.active"      },
+  { "menu.button_quit",                                        UNDEFINED_FILENAME              },
+  { "menu.button_quit.clone_from",                     "menu.button"                   },
+  { "menu.button_quit.active",                         UNDEFINED_FILENAME              },
+  { "menu.button_quit.active.clone_from",              "menu.button.active"            },
+
+  { "menu.button_first_level",                         UNDEFINED_FILENAME              },
+  { "menu.button_first_level.active",                  UNDEFINED_FILENAME              },
+  { "menu.button_last_level",                          UNDEFINED_FILENAME              },
+  { "menu.button_last_level.active",                   UNDEFINED_FILENAME              },
+  { "menu.button_level_number",                                UNDEFINED_FILENAME              },
+  { "menu.button_level_number.active",                 UNDEFINED_FILENAME              },
+
+  { "menu.button_insert_solution",                     UNDEFINED_FILENAME              },
+  { "menu.button_insert_solution.active",              UNDEFINED_FILENAME              },
+  { "menu.button_play_solution",                       UNDEFINED_FILENAME              },
+  { "menu.button_play_solution.active",                        UNDEFINED_FILENAME              },
+
+  { "menu.button_levelset_info",                       UNDEFINED_FILENAME              },
+  { "menu.button_levelset_info.clone_from",            "envelope_1"                    },
+  { "menu.button_levelset_info.pressed",               UNDEFINED_FILENAME              },
+  { "menu.button_levelset_info.pressed.clone_from",    "envelope_1.collecting"         },
+  { "menu.button_levelset_info.active",                        UNDEFINED_FILENAME              },
+  { "menu.button_levelset_info.active.clone_from",     "envelope_1"                    },
+
+  { "menu.button_switch_ecs_aga",                      UNDEFINED_FILENAME              },
+  { "menu.button_switch_ecs_aga.active",               UNDEFINED_FILENAME              },
+
+  { "menu.button_touch_back",                          "RocksTouch.png"                },
+  { "menu.button_touch_back.x",                                "210"                           },
+  { "menu.button_touch_back.y",                                "180"                           },
+  { "menu.button_touch_back.width",                    "60"                            },
+  { "menu.button_touch_back.height",                   "60"                            },
+  { "menu.button_touch_back.pressed_xoffset",          "-200"                          },
+  { "menu.button_touch_next",                          "RocksTouch.png"                },
+  { "menu.button_touch_next.x",                                "330"                           },
+  { "menu.button_touch_next.y",                                "180"                           },
+  { "menu.button_touch_next.width",                    "60"                            },
+  { "menu.button_touch_next.height",                   "60"                            },
+  { "menu.button_touch_next.pressed_xoffset",          "-200"                          },
+  { "menu.button_touch_back2",                         "RocksTouch.png"                },
+  { "menu.button_touch_back2.x",                       "210"                           },
+  { "menu.button_touch_back2.y",                       "180"                           },
+  { "menu.button_touch_back2.width",                   "60"                            },
+  { "menu.button_touch_back2.height",                  "60"                            },
+  { "menu.button_touch_back2.pressed_xoffset",         "-200"                          },
+  { "menu.button_touch_next2",                         "RocksTouch.png"                },
+  { "menu.button_touch_next2.x",                       "330"                           },
+  { "menu.button_touch_next2.y",                       "180"                           },
+  { "menu.button_touch_next2.width",                   "60"                            },
+  { "menu.button_touch_next2.height",                  "60"                            },
+  { "menu.button_touch_next2.pressed_xoffset",         "-200"                          },
+
+  { "menu.scrollbar",                                  "RocksDC.png"                   },
+  { "menu.scrollbar.xpos",                             "8"                             },
+  { "menu.scrollbar.ypos",                             "10"                            },
+  { "menu.scrollbar.frames",                           "1"                             },
+  { "menu.scrollbar.active",                           "RocksDC.png"                   },
+  { "menu.scrollbar.active.xpos",                      "9"                             },
+  { "menu.scrollbar.active.ypos",                      "10"                            },
+  { "menu.scrollbar.active.frames",                    "1"                             },
+
+  { "gfx.game.panel.time_anim",                                "RocksDoorMM.png"               },
+  { "gfx.game.panel.time_anim.x",                      "5"                             },
+  { "gfx.game.panel.time_anim.y",                      "0"                             },
+  { "gfx.game.panel.time_anim.width",                  "90"                            },
+  { "gfx.game.panel.time_anim.height",                 "35"                            },
+  { "gfx.game.panel.time_anim.frames",                 "1"                             },
+  { "gfx.game.panel.time_anim.active",                 "RocksDoorMM.png"               },
+  { "gfx.game.panel.time_anim.active.x",               "105"                           },
+  { "gfx.game.panel.time_anim.active.y",               "0"                             },
+  { "gfx.game.panel.time_anim.active.width",           "90"                            },
+  { "gfx.game.panel.time_anim.active.height",          "35"                            },
+  { "gfx.game.panel.time_anim.active.frames",          "1"                             },
+
+  { "gfx.game.panel.health_anim",                      "RocksDoorMM.png"               },
+  { "gfx.game.panel.health_anim.x",                    "5"                             },
+  { "gfx.game.panel.health_anim.y",                    "35"                            },
+  { "gfx.game.panel.health_anim.width",                        "90"                            },
+  { "gfx.game.panel.health_anim.height",               "35"                            },
+  { "gfx.game.panel.health_anim.frames",               "1"                             },
+  { "gfx.game.panel.health_anim.active",               "RocksDoorMM.png"               },
+  { "gfx.game.panel.health_anim.active.x",             "105"                           },
+  { "gfx.game.panel.health_anim.active.y",             "35"                            },
+  { "gfx.game.panel.health_anim.active.width",         "90"                            },
+  { "gfx.game.panel.health_anim.active.height",                "35"                            },
+  { "gfx.game.panel.health_anim.active.frames",                "1"                             },
+
+  { "gfx.game.button.stop",                            "RocksDoor.png"                 },
+  { "gfx.game.button.stop.x",                          "305"                           },
+  { "gfx.game.button.stop.y",                          "185"                           },
+  { "gfx.game.button.stop.width",                      "30"                            },
+  { "gfx.game.button.stop.height",                     "30"                            },
+  { "gfx.game.button.stop.pressed_xoffset",            "-100"                          },
+  { "gfx.game.button.pause",                           "RocksDoor.png"                 },
+  { "gfx.game.button.pause.x",                         "335"                           },
+  { "gfx.game.button.pause.y",                         "185"                           },
+  { "gfx.game.button.pause.width",                     "30"                            },
+  { "gfx.game.button.pause.height",                    "30"                            },
+  { "gfx.game.button.pause.pressed_xoffset",           "-100"                          },
+  { "gfx.game.button.play",                            "RocksDoor.png"                 },
+  { "gfx.game.button.play.x",                          "365"                           },
+  { "gfx.game.button.play.y",                          "185"                           },
+  { "gfx.game.button.play.width",                      "30"                            },
+  { "gfx.game.button.play.height",                     "30"                            },
+  { "gfx.game.button.play.pressed_xoffset",            "-100"                          },
+
+  { "gfx.game.button.undo",                            "RocksDoor2.png"                },
+  { "gfx.game.button.undo.x",                          "105"                           },
+  { "gfx.game.button.undo.y",                          "20"                            },
+  { "gfx.game.button.undo.width",                      "30"                            },
+  { "gfx.game.button.undo.height",                     "30"                            },
+  { "gfx.game.button.undo.pressed_xoffset",            "-100"                          },
+  { "gfx.game.button.redo",                            "RocksDoor2.png"                },
+  { "gfx.game.button.redo.x",                          "165"                           },
+  { "gfx.game.button.redo.y",                          "20"                            },
+  { "gfx.game.button.redo.width",                      "30"                            },
+  { "gfx.game.button.redo.height",                     "30"                            },
+  { "gfx.game.button.redo.pressed_xoffset",            "-100"                          },
+
+  { "gfx.game.button.save",                            "RocksDoor2.png"                },
+  { "gfx.game.button.save.x",                          "105"                           },
+  { "gfx.game.button.save.y",                          "50"                            },
+  { "gfx.game.button.save.width",                      "30"                            },
+  { "gfx.game.button.save.height",                     "30"                            },
+  { "gfx.game.button.save.pressed_xoffset",            "-100"                          },
+  { "gfx.game.button.pause2",                          "RocksDoor2.png"                },
+  { "gfx.game.button.pause2.x",                                "135"                           },
+  { "gfx.game.button.pause2.y",                                "50"                            },
+  { "gfx.game.button.pause2.width",                    "30"                            },
+  { "gfx.game.button.pause2.height",                   "30"                            },
+  { "gfx.game.button.pause2.pressed_xoffset",          "-100"                          },
+  { "gfx.game.button.pause2.active_yoffset",           "-30"                           },
+  { "gfx.game.button.load",                            "RocksDoor2.png"                },
+  { "gfx.game.button.load.x",                          "165"                           },
+  { "gfx.game.button.load.y",                          "50"                            },
+  { "gfx.game.button.load.width",                      "30"                            },
+  { "gfx.game.button.load.height",                     "30"                            },
+  { "gfx.game.button.load.pressed_xoffset",            "-100"                          },
+
+  { "gfx.game.button.restart",                         "RocksDoor2.png"                },
+  { "gfx.game.button.restart.x",                       "200"                           },
+  { "gfx.game.button.restart.y",                       "50"                            },
+  { "gfx.game.button.restart.width",                   "30"                            },
+  { "gfx.game.button.restart.height",                  "30"                            },
+  { "gfx.game.button.restart.pressed_xoffset",         "30"                            },
+
+  { "gfx.game.button.sound_music",                     "RocksDoor.png"                 },
+  { "gfx.game.button.sound_music.x",                   "305"                           },
+  { "gfx.game.button.sound_music.y",                   "245"                           },
+  { "gfx.game.button.sound_music.width",               "30"                            },
+  { "gfx.game.button.sound_music.height",              "30"                            },
+  { "gfx.game.button.sound_music.pressed_xoffset",     "-100"                          },
+  { "gfx.game.button.sound_music.active_yoffset",      "-30"                           },
+  { "gfx.game.button.sound_loops",                     "RocksDoor.png"                 },
+  { "gfx.game.button.sound_loops.x",                   "335"                           },
+  { "gfx.game.button.sound_loops.y",                   "245"                           },
+  { "gfx.game.button.sound_loops.width",               "30"                            },
+  { "gfx.game.button.sound_loops.height",              "30"                            },
+  { "gfx.game.button.sound_loops.pressed_xoffset",     "-100"                          },
+  { "gfx.game.button.sound_loops.active_yoffset",      "-30"                           },
+  { "gfx.game.button.sound_simple",                    "RocksDoor.png"                 },
+  { "gfx.game.button.sound_simple.x",                  "365"                           },
+  { "gfx.game.button.sound_simple.y",                  "245"                           },
+  { "gfx.game.button.sound_simple.width",              "30"                            },
+  { "gfx.game.button.sound_simple.height",             "30"                            },
+  { "gfx.game.button.sound_simple.pressed_xoffset",    "-100"                          },
+  { "gfx.game.button.sound_simple.active_yoffset",     "-30"                           },
+
+  { "gfx.game.button.panel_stop",                      UNDEFINED_FILENAME              },
+  { "gfx.game.button.panel_pause",                     UNDEFINED_FILENAME              },
+  { "gfx.game.button.panel_play",                      UNDEFINED_FILENAME              },
+  { "gfx.game.button.panel_restart",                   UNDEFINED_FILENAME              },
+
+  { "gfx.game.button.panel_sound_music",               UNDEFINED_FILENAME              },
+  { "gfx.game.button.panel_sound_loops",               UNDEFINED_FILENAME              },
+  { "gfx.game.button.panel_sound_simple",              UNDEFINED_FILENAME              },
+
+  { "gfx.game.button.touch_stop",                      "RocksTouch.png"                },
+  { "gfx.game.button.touch_stop.x",                    "210"                           },
+  { "gfx.game.button.touch_stop.y",                    "120"                           },
+  { "gfx.game.button.touch_stop.width",                        "60"                            },
+  { "gfx.game.button.touch_stop.height",               "60"                            },
+  { "gfx.game.button.touch_stop.pressed_xoffset",      "-200"                          },
+  { "gfx.game.button.touch_pause",                     "RocksTouch.png"                },
+  { "gfx.game.button.touch_pause.x",                   "270"                           },
+  { "gfx.game.button.touch_pause.y",                   "120"                           },
+  { "gfx.game.button.touch_pause.width",               "60"                            },
+  { "gfx.game.button.touch_pause.height",              "60"                            },
+  { "gfx.game.button.touch_pause.pressed_xoffset",     "-200"                          },
+  { "gfx.game.button.touch_pause.active_yoffset",      "60"                            },
+
+  { "gfx.game.button.touch_restart",                   "RocksTouch.png"                },
+  { "gfx.game.button.touch_restart.x",                 "210"                           },
+  { "gfx.game.button.touch_restart.y",                 "240"                           },
+  { "gfx.game.button.touch_restart.width",             "60"                            },
+  { "gfx.game.button.touch_restart.height",            "60"                            },
+  { "gfx.game.button.touch_restart.pressed_xoffset",   "-200"                          },
+
+  { "gfx.tape.button.eject",                           "RocksDoor.png"                 },
+  { "gfx.tape.button.eject.x",                         "305"                           },
+  { "gfx.tape.button.eject.y",                         "357"                           },
+  { "gfx.tape.button.eject.width",                     "18"                            },
+  { "gfx.tape.button.eject.height",                    "18"                            },
+  { "gfx.tape.button.eject.pressed_xoffset",           "-100"                          },
+  { "gfx.tape.button.extra",                           "RocksDoor.png"                 },
+  { "gfx.tape.button.extra.x",                         "505"                           },
+  { "gfx.tape.button.extra.y",                         "357"                           },
+  { "gfx.tape.button.extra.width",                     "18"                            },
+  { "gfx.tape.button.extra.height",                    "18"                            },
+  { "gfx.tape.button.extra.pressed_xoffset",           "-100"                          },
+  { "gfx.tape.button.stop",                            "RocksDoor.png"                 },
+  { "gfx.tape.button.stop.x",                          "323"                           },
+  { "gfx.tape.button.stop.y",                          "357"                           },
+  { "gfx.tape.button.stop.width",                      "18"                            },
+  { "gfx.tape.button.stop.height",                     "18"                            },
+  { "gfx.tape.button.stop.pressed_xoffset",            "-100"                          },
+  { "gfx.tape.button.pause",                           "RocksDoor.png"                 },
+  { "gfx.tape.button.pause.x",                         "341"                           },
+  { "gfx.tape.button.pause.y",                         "357"                           },
+  { "gfx.tape.button.pause.width",                     "18"                            },
+  { "gfx.tape.button.pause.height",                    "18"                            },
+  { "gfx.tape.button.pause.pressed_xoffset",           "-100"                          },
+  { "gfx.tape.button.record",                          "RocksDoor.png"                 },
+  { "gfx.tape.button.record.x",                                "359"                           },
+  { "gfx.tape.button.record.y",                                "357"                           },
+  { "gfx.tape.button.record.width",                    "18"                            },
+  { "gfx.tape.button.record.height",                   "18"                            },
+  { "gfx.tape.button.record.pressed_xoffset",          "-100"                          },
+  { "gfx.tape.button.play",                            "RocksDoor.png"                 },
+  { "gfx.tape.button.play.x",                          "377"                           },
+  { "gfx.tape.button.play.y",                          "357"                           },
+  { "gfx.tape.button.play.width",                      "18"                            },
+  { "gfx.tape.button.play.height",                     "18"                            },
+  { "gfx.tape.button.play.pressed_xoffset",            "-100"                          },
+
+  { "gfx.tape.button.insert_solution",                 UNDEFINED_FILENAME              },
+  { "gfx.tape.button.play_solution",                   UNDEFINED_FILENAME              },
+
+  { "gfx.tape.symbol.eject",                           UNDEFINED_FILENAME              },
+  { "gfx.tape.symbol.stop",                            UNDEFINED_FILENAME              },
+  { "gfx.tape.symbol.pause",                           "RocksDoor.png"                 },
+  { "gfx.tape.symbol.pause.x",                         "340"                           },
+  { "gfx.tape.symbol.pause.y",                         "321"                           },
+  { "gfx.tape.symbol.pause.width",                     "17"                            },
+  { "gfx.tape.symbol.pause.height",                    "13"                            },
+  { "gfx.tape.symbol.record",                          "RocksDoor.png"                 },
+  { "gfx.tape.symbol.record.x",                                "325"                           },
+  { "gfx.tape.symbol.record.y",                                "321"                           },
+  { "gfx.tape.symbol.record.width",                    "16"                            },
+  { "gfx.tape.symbol.record.height",                   "16"                            },
+  { "gfx.tape.symbol.play",                            "RocksDoor.png"                 },
+  { "gfx.tape.symbol.play.x",                          "357"                           },
+  { "gfx.tape.symbol.play.y",                          "321"                           },
+  { "gfx.tape.symbol.play.width",                      "11"                            },
+  { "gfx.tape.symbol.play.height",                     "13"                            },
+  { "gfx.tape.symbol.fast_forward",                    "RocksDoor.png"                 },
+  { "gfx.tape.symbol.fast_forward.x",                  "539"                           },
+  { "gfx.tape.symbol.fast_forward.y",                  "193"                           },
+  { "gfx.tape.symbol.fast_forward.width",              "27"                            },
+  { "gfx.tape.symbol.fast_forward.height",             "13"                            },
+  { "gfx.tape.symbol.warp_forward",                    "RocksDoor.png"                 },
+  { "gfx.tape.symbol.warp_forward.x",                  "539"                           },
+  { "gfx.tape.symbol.warp_forward.y",                  "152"                           },
+  { "gfx.tape.symbol.warp_forward.width",              "27"                            },
+  { "gfx.tape.symbol.warp_forward.height",             "13"                            },
+  { "gfx.tape.symbol.warp_forward_blind",              "RocksDoor.png"                 },
+  { "gfx.tape.symbol.warp_forward_blind.x",            "539"                           },
+  { "gfx.tape.symbol.warp_forward_blind.y",            "165"                           },
+  { "gfx.tape.symbol.warp_forward_blind.width",                "27"                            },
+  { "gfx.tape.symbol.warp_forward_blind.height",       "13"                            },
+  { "gfx.tape.symbol.pause_before_end",                        "RocksDoor.png"                 },
+  { "gfx.tape.symbol.pause_before_end.x",              "539"                           },
+  { "gfx.tape.symbol.pause_before_end.y",              "221"                           },
+  { "gfx.tape.symbol.pause_before_end.width",          "27"                            },
+  { "gfx.tape.symbol.pause_before_end.height",         "13"                            },
+  { "gfx.tape.symbol.single_step",                     UNDEFINED_FILENAME              },
+
+  { "gfx.tape.label.eject",                            UNDEFINED_FILENAME              },
+  { "gfx.tape.label.stop",                             UNDEFINED_FILENAME              },
+  { "gfx.tape.label.pause",                            "RocksDoor.png"                 },
+  { "gfx.tape.label.pause.x",                          "305"                           },
+  { "gfx.tape.label.pause.y",                          "341"                           },
+  { "gfx.tape.label.pause.width",                      "35"                            },
+  { "gfx.tape.label.pause.height",                     "8"                             },
+  { "gfx.tape.label.record",                           "RocksDoor.png"                 },
+  { "gfx.tape.label.record.x",                         "305"                           },
+  { "gfx.tape.label.record.y",                         "321"                           },
+  { "gfx.tape.label.record.width",                     "20"                            },
+  { "gfx.tape.label.record.height",                    "12"                            },
+  { "gfx.tape.label.play",                             "RocksDoor.png"                 },
+  { "gfx.tape.label.play.x",                           "370"                           },
+  { "gfx.tape.label.play.y",                           "321"                           },
+  { "gfx.tape.label.play.width",                       "22"                            },
+  { "gfx.tape.label.play.height",                      "12"                            },
+  { "gfx.tape.label.fast_forward",                     "RocksDoor.png"                 },
+  { "gfx.tape.label.fast_forward.x",                   "505"                           },
+  { "gfx.tape.label.fast_forward.y",                   "193"                           },
+  { "gfx.tape.label.fast_forward.width",               "40"                            },
+  { "gfx.tape.label.fast_forward.height",              "28"                            },
+  { "gfx.tape.label.warp_forward",                     "RocksDoor.png"                 },
+  { "gfx.tape.label.warp_forward.x",                   "505"                           },
+  { "gfx.tape.label.warp_forward.y",                   "165"                           },
+  { "gfx.tape.label.warp_forward.width",               "40"                            },
+  { "gfx.tape.label.warp_forward.height",              "28"                            },
+  { "gfx.tape.label.warp_forward_blind",               "RocksDoor.png"                 },
+  { "gfx.tape.label.warp_forward_blind.x",             "505"                           },
+  { "gfx.tape.label.warp_forward_blind.y",             "165"                           },
+  { "gfx.tape.label.warp_forward_blind.width",         "40"                            },
+  { "gfx.tape.label.warp_forward_blind.height",                "28"                            },
+  { "gfx.tape.label.pause_before_end",                 "RocksDoor.png"                 },
+  { "gfx.tape.label.pause_before_end.x",               "505"                           },
+  { "gfx.tape.label.pause_before_end.y",               "221"                           },
+  { "gfx.tape.label.pause_before_end.width",           "40"                            },
+  { "gfx.tape.label.pause_before_end.height",          "28"                            },
+  { "gfx.tape.label.single_step",                      "RocksDoor.png"                 },
+  { "gfx.tape.label.single_step.x",                    "557"                           },
+  { "gfx.tape.label.single_step.y",                    "139"                           },
+  { "gfx.tape.label.single_step.width",                        "38"                            },
+  { "gfx.tape.label.single_step.height",               "13"                            },
+
+  { "gfx.tape.label.date",                             "RocksDoor.png"                 },
+  { "gfx.tape.label.date.x",                           "305"                           },
+  { "gfx.tape.label.date.y",                           "285"                           },
+  { "gfx.tape.label.date.width",                       "90"                            },
+  { "gfx.tape.label.date.height",                      "31"                            },
+  { "gfx.tape.label.time",                             "RocksDoor.png"                 },
+  { "gfx.tape.label.time.x",                           "346"                           },
+  { "gfx.tape.label.time.y",                           "335"                           },
+  { "gfx.tape.label.time.width",                       "45"                            },
+  { "gfx.tape.label.time.height",                      "13"                            },
+
+  { "gfx.request.button.yes",                          "RocksDoor.png"                 },
+  { "gfx.request.button.yes.x",                                "302"                           },
+  { "gfx.request.button.yes.y",                                "0"                             },
+  { "gfx.request.button.yes.width",                    "46"                            },
+  { "gfx.request.button.yes.height",                   "28"                            },
+  { "gfx.request.button.yes.pressed_xoffset",          "-100"                          },
+  { "gfx.request.button.no",                           "RocksDoor.png"                 },
+  { "gfx.request.button.no.x",                         "352"                           },
+  { "gfx.request.button.no.y",                         "0"                             },
+  { "gfx.request.button.no.width",                     "46"                            },
+  { "gfx.request.button.no.height",                    "28"                            },
+  { "gfx.request.button.no.pressed_xoffset",           "-100"                          },
+  { "gfx.request.button.confirm",                      "RocksDoor.png"                 },
+  { "gfx.request.button.confirm.x",                    "302"                           },
+  { "gfx.request.button.confirm.y",                    "30"                            },
+  { "gfx.request.button.confirm.width",                        "96"                            },
+  { "gfx.request.button.confirm.height",               "28"                            },
+  { "gfx.request.button.confirm.pressed_xoffset",      "-100"                          },
+  { "gfx.request.button.player_1",                     "RocksDoor.png"                 },
+  { "gfx.request.button.player_1.x",                   "305"                           },
+  { "gfx.request.button.player_1.y",                   "185"                           },
+  { "gfx.request.button.player_1.width",               "30"                            },
+  { "gfx.request.button.player_1.height",              "30"                            },
+  { "gfx.request.button.player_1.pressed_xoffset",     "-100"                          },
+  { "gfx.request.button.player_2",                     UNDEFINED_FILENAME              },
+  { "gfx.request.button.player_2.clone_from",          "gfx.request.button.player_1"   },
+  { "gfx.request.button.player_3",                     UNDEFINED_FILENAME              },
+  { "gfx.request.button.player_3.clone_from",          "gfx.request.button.player_1"   },
+  { "gfx.request.button.player_4",                     UNDEFINED_FILENAME              },
+  { "gfx.request.button.player_4.clone_from",          "gfx.request.button.player_1"   },
+
+  { "gfx.request.button.touch_yes",                    "RocksTouch.png"                },
+  { "gfx.request.button.touch_yes.x",                  "204"                           },
+  { "gfx.request.button.touch_yes.y",                  "0"                             },
+  { "gfx.request.button.touch_yes.width",              "92"                            },
+  { "gfx.request.button.touch_yes.height",             "56"                            },
+  { "gfx.request.button.touch_yes.pressed_xoffset",    "-200"                          },
+  { "gfx.request.button.touch_no",                     "RocksTouch.png"                },
+  { "gfx.request.button.touch_no.x",                   "304"                           },
+  { "gfx.request.button.touch_no.y",                   "0"                             },
+  { "gfx.request.button.touch_no.width",               "92"                            },
+  { "gfx.request.button.touch_no.height",              "56"                            },
+  { "gfx.request.button.touch_no.pressed_xoffset",     "-200"                          },
+  { "gfx.request.button.touch_confirm",                        "RocksTouch.png"                },
+  { "gfx.request.button.touch_confirm.x",              "204"                           },
+  { "gfx.request.button.touch_confirm.y",              "60"                            },
+  { "gfx.request.button.touch_confirm.width",          "192"                           },
+  { "gfx.request.button.touch_confirm.height",         "56"                            },
+  { "gfx.request.button.touch_confirm.pressed_xoffset",        "-200"                          },
+
+  { "font.initial_1",                                  "RocksFontSmall.png"            },
+  { "font.initial_1.x",                                        "0"                             },
+  { "font.initial_1.y",                                        "0"                             },
+  { "font.initial_1.width",                            "14"                            },
+  { "font.initial_1.height",                           "14"                            },
+  { "font.initial_2",                                  "RocksFontSmall.png"            },
+  { "font.initial_2.x",                                        "0"                             },
+  { "font.initial_2.y",                                        "70"                            },
+  { "font.initial_2.width",                            "14"                            },
+  { "font.initial_2.height",                           "14"                            },
+  { "font.initial_3",                                  "RocksFontSmall.png"            },
+  { "font.initial_3.x",                                        "0"                             },
+  { "font.initial_3.y",                                        "140"                           },
+  { "font.initial_3.width",                            "14"                            },
+  { "font.initial_3.height",                           "14"                            },
+  { "font.initial_4",                                  "RocksFontSmall.png"            },
+  { "font.initial_4.x",                                        "0"                             },
+  { "font.initial_4.y",                                        "210"                           },
+  { "font.initial_4.width",                            "14"                            },
+  { "font.initial_4.height",                           "14"                            },
+
+  { "font.title_1",                                    "RocksFontBig.png"              },
+  { "font.title_1.x",                                  "0"                             },
+  { "font.title_1.y",                                  "480"                           },
+  { "font.title_1.width",                              "32"                            },
+  { "font.title_1.height",                             "32"                            },
+  { "font.title_2",                                    "RocksFontSmall.png"            },
+  { "font.title_2.x",                                  "0"                             },
+  { "font.title_2.y",                                  "0"                             },
+  { "font.title_2.width",                              "14"                            },
+  { "font.title_2.height",                             "14"                            },
+  { "font.title_2.SETUP",                              UNDEFINED_FILENAME              },
+  { "font.title_2.SETUP.clone_from",                   "font.text_2"                   },
+
+  { "font.menu_1",                                     "RocksFontBig.png"              },
+  { "font.menu_1.x",                                   "0"                             },
+  { "font.menu_1.y",                                   "320"                           },
+  { "font.menu_1.width",                               "32"                            },
+  { "font.menu_1.height",                              "32"                            },
+  { "font.menu_1.active",                              "RocksFontBig.png"              },
+  { "font.menu_1.active.x",                            "0"                             },
+  { "font.menu_1.active.y",                            "480"                           },
+  { "font.menu_1.active.width",                                "32"                            },
+  { "font.menu_1.active.height",                       "32"                            },
+  { "font.menu_2",                                     "RocksFontMedium.png"           },
+  { "font.menu_2.x",                                   "0"                             },
+  { "font.menu_2.y",                                   "320"                           },
+  { "font.menu_2.width",                               "16"                            },
+  { "font.menu_2.height",                              "32"                            },
+  { "font.menu_2.active",                              "RocksFontMedium.png"           },
+  { "font.menu_2.active.x",                            "0"                             },
+  { "font.menu_2.active.y",                            "480"                           },
+  { "font.menu_2.active.width",                                "16"                            },
+  { "font.menu_2.active.height",                       "32"                            },
+
+  { "font.text_1",                                     "RocksFontSmall.png"            },
+  { "font.text_1.x",                                   "0"                             },
+  { "font.text_1.y",                                   "140"                           },
+  { "font.text_1.width",                               "14"                            },
+  { "font.text_1.height",                              "14"                            },
+  { "font.text_1.MAIN",                                        UNDEFINED_FILENAME              },
+  { "font.text_1.MAIN.clone_from",                     "font.text_1.PREVIEW"           },
+  { "font.text_1.LEVELS",                              "RocksFontMedium.png"           },
+  { "font.text_1.LEVELS.x",                            "0"                             },
+  { "font.text_1.LEVELS.y",                            "0"                             },
+  { "font.text_1.LEVELS.width",                                "16"                            },
+  { "font.text_1.LEVELS.height",                       "32"                            },
+  { "font.text_1.LEVELNR",                             UNDEFINED_FILENAME              },
+  { "font.text_1.LEVELNR.clone_from",                  "font.text_1.LEVELS"            },
+  { "font.text_1.SETUP",                               UNDEFINED_FILENAME              },
+  { "font.text_1.SETUP.clone_from",                    "font.text_1.LEVELS"            },
+  { "font.text_1.NAMES",                               UNDEFINED_FILENAME              },
+  { "font.text_1.NAMES.clone_from",                    "font.input_1.MAIN"             },
+  { "font.text_1.PREVIEW",                             "RocksFontEM.png"               },
+  { "font.text_1.PREVIEW.x",                           "0"                             },
+  { "font.text_1.PREVIEW.y",                           "160"                           },
+  { "font.text_1.PREVIEW.width",                       "16"                            },
+  { "font.text_1.PREVIEW.height",                      "16"                            },
+  { "font.text_1.SCORES",                              "RocksFontMedium.png"           },
+  { "font.text_1.SCORES.x",                            "0"                             },
+  { "font.text_1.SCORES.y",                            "480"                           },
+  { "font.text_1.SCORES.width",                                "16"                            },
+  { "font.text_1.SCORES.height",                       "32"                            },
+  { "font.text_1.active.SCORES",                       "RocksFontMedium.png"           },
+  { "font.text_1.active.SCORES.x",                     "0"                             },
+  { "font.text_1.active.SCORES.y",                     "0"                             },
+  { "font.text_1.active.SCORES.width",                 "16"                            },
+  { "font.text_1.active.SCORES.height",                        "32"                            },
+  { "font.text_1.PANEL",                               UNDEFINED_FILENAME              },
+  { "font.text_1.PANEL.clone_from",                    "font.level_number"             },
+  { "font.text_1.DOOR",                                        UNDEFINED_FILENAME              },
+  { "font.text_1.DOOR.clone_from",                     "font.level_number"             },
+  { "font.text_2",                                     "RocksFontSmall.png"            },
+  { "font.text_2.x",                                   "0"                             },
+  { "font.text_2.y",                                   "210"                           },
+  { "font.text_2.width",                               "14"                            },
+  { "font.text_2.height",                              "14"                            },
+  { "font.text_2.MAIN",                                        UNDEFINED_FILENAME              },
+  { "font.text_2.MAIN.clone_from",                     "font.text_2.PREVIEW"           },
+  { "font.text_2.LEVELS",                              "RocksFontMedium.png"           },
+  { "font.text_2.LEVELS.x",                            "0"                             },
+  { "font.text_2.LEVELS.y",                            "160"                           },
+  { "font.text_2.LEVELS.width",                                "16"                            },
+  { "font.text_2.LEVELS.height",                       "32"                            },
+  { "font.text_2.LEVELNR",                             UNDEFINED_FILENAME              },
+  { "font.text_2.LEVELNR.clone_from",                  "font.text_2.LEVELS"            },
+  { "font.text_2.SETUP",                               UNDEFINED_FILENAME              },
+  { "font.text_2.SETUP.clone_from",                    "font.text_2.LEVELS"            },
+  { "font.text_2.NAMES",                               UNDEFINED_FILENAME              },
+  { "font.text_2.NAMES.clone_from",                    "font.option_off"               },
+  { "font.text_2.PREVIEW",                             "RocksFontEM.png"               },
+  { "font.text_2.PREVIEW.x",                           "0"                             },
+  { "font.text_2.PREVIEW.y",                           "160"                           },
+  { "font.text_2.PREVIEW.width",                       "16"                            },
+  { "font.text_2.PREVIEW.height",                      "16"                            },
+  { "font.text_2.SCORES",                              "RocksFontBig.png"              },
+  { "font.text_2.SCORES.x",                            "0"                             },
+  { "font.text_2.SCORES.y",                            "320"                           },
+  { "font.text_2.SCORES.width",                                "32"                            },
+  { "font.text_2.SCORES.height",                       "32"                            },
+  { "font.text_2.active.SCORES",                       "RocksFontBig.png"              },
+  { "font.text_2.active.SCORES.x",                     "0"                             },
+  { "font.text_2.active.SCORES.y",                     "0"                             },
+  { "font.text_2.active.SCORES.width",                 "32"                            },
+  { "font.text_2.active.SCORES.height",                        "32"                            },
+  { "font.text_3",                                     "RocksFontSmall.png"            },
+  { "font.text_3.x",                                   "0"                             },
+  { "font.text_3.y",                                   "0"                             },
+  { "font.text_3.width",                               "14"                            },
+  { "font.text_3.height",                              "14"                            },
+  { "font.text_3.LEVELS",                              "RocksFontMedium.png"           },
+  { "font.text_3.LEVELS.x",                            "0"                             },
+  { "font.text_3.LEVELS.y",                            "320"                           },
+  { "font.text_3.LEVELS.width",                                "16"                            },
+  { "font.text_3.LEVELS.height",                       "32"                            },
+  { "font.text_3.LEVELNR",                             UNDEFINED_FILENAME              },
+  { "font.text_3.LEVELNR.clone_from",                  "font.text_3.LEVELS"            },
+  { "font.text_3.SETUP",                               UNDEFINED_FILENAME              },
+  { "font.text_3.SETUP.clone_from",                    "font.text_3.LEVELS"            },
+  { "font.text_3.NAMES",                               UNDEFINED_FILENAME              },
+  { "font.text_3.NAMES.clone_from",                    "font.menu_1"                   },
+  { "font.text_3.PREVIEW",                             "RocksFontEM.png"               },
+  { "font.text_3.PREVIEW.x",                           "0"                             },
+  { "font.text_3.PREVIEW.y",                           "160"                           },
+  { "font.text_3.PREVIEW.width",                       "16"                            },
+  { "font.text_3.PREVIEW.height",                      "16"                            },
+  { "font.text_3.SCORES",                              "RocksFontMedium.png"           },
+  { "font.text_3.SCORES.x",                            "0"                             },
+  { "font.text_3.SCORES.y",                            "480"                           },
+  { "font.text_3.SCORES.width",                                "16"                            },
+  { "font.text_3.SCORES.height",                       "32"                            },
+  { "font.text_3.active.SCORES",                       "RocksFontMedium.png"           },
+  { "font.text_3.active.SCORES.x",                     "0"                             },
+  { "font.text_3.active.SCORES.y",                     "0"                             },
+  { "font.text_3.active.SCORES.width",                 "16"                            },
+  { "font.text_3.active.SCORES.height",                        "32"                            },
+  { "font.text_4",                                     "RocksFontSmall.png"            },
+  { "font.text_4.x",                                   "0"                             },
+  { "font.text_4.y",                                   "70"                            },
+  { "font.text_4.width",                               "14"                            },
+  { "font.text_4.height",                              "14"                            },
+  { "font.text_4.MAIN",                                        UNDEFINED_FILENAME              },
+  { "font.text_4.MAIN.clone_from",                     "font.text_3.PREVIEW"           },
+  { "font.text_4.LEVELS",                              "RocksFontMedium.png"           },
+  { "font.text_4.LEVELS.x",                            "0"                             },
+  { "font.text_4.LEVELS.y",                            "480"                           },
+  { "font.text_4.LEVELS.width",                                "16"                            },
+  { "font.text_4.LEVELS.height",                       "32"                            },
+  { "font.text_4.LEVELNR",                             UNDEFINED_FILENAME              },
+  { "font.text_4.LEVELNR.clone_from",                  "font.text_4.LEVELS"            },
+  { "font.text_4.SETUP",                               UNDEFINED_FILENAME              },
+  { "font.text_4.SETUP.clone_from",                    "font.text_4.LEVELS"            },
+  { "font.text_4.NAMES",                               UNDEFINED_FILENAME              },
+  { "font.text_4.NAMES.clone_from",                    "font.menu_1.active"            },
+  { "font.text_4.SCORES",                              "RocksFontMedium.png"           },
+  { "font.text_4.SCORES.x",                            "0"                             },
+  { "font.text_4.SCORES.y",                            "480"                           },
+  { "font.text_4.SCORES.width",                                "16"                            },
+  { "font.text_4.SCORES.height",                       "32"                            },
+  { "font.text_4.active.SCORES",                       "RocksFontMedium.png"           },
+  { "font.text_4.active.SCORES.x",                     "0"                             },
+  { "font.text_4.active.SCORES.y",                     "0"                             },
+  { "font.text_4.active.SCORES.width",                 "16"                            },
+  { "font.text_4.active.SCORES.height",                        "32"                            },
+
+  { "font.envelope_1",                                 "RocksFontEM.png"               },
+  { "font.envelope_1.x",                               "0"                             },
+  { "font.envelope_1.y",                               "160"                           },
+  { "font.envelope_1.width",                           "16"                            },
+  { "font.envelope_1.height",                          "16"                            },
+  { "font.envelope_2",                                 "RocksFontEM.png"               },
+  { "font.envelope_2.x",                               "0"                             },
+  { "font.envelope_2.y",                               "160"                           },
+  { "font.envelope_2.width",                           "16"                            },
+  { "font.envelope_2.height",                          "16"                            },
+  { "font.envelope_3",                                 "RocksFontEM.png"               },
+  { "font.envelope_3.x",                               "0"                             },
+  { "font.envelope_3.y",                               "160"                           },
+  { "font.envelope_3.width",                           "16"                            },
+  { "font.envelope_3.height",                          "16"                            },
+  { "font.envelope_4",                                 "RocksFontEM.png"               },
+  { "font.envelope_4.x",                               "0"                             },
+  { "font.envelope_4.y",                               "160"                           },
+  { "font.envelope_4.width",                           "16"                            },
+  { "font.envelope_4.height",                          "16"                            },
+
+  { "font.request",                                    "RocksFontSmall.png"            },
+  { "font.request.x",                                  "0"                             },
+  { "font.request.y",                                  "210"                           },
+  { "font.request.width",                              "14"                            },
+  { "font.request.height",                             "14"                            },
+  { "font.request_narrow",                             UNDEFINED_FILENAME              },
+  { "font.request_narrow.clone_from",                  "font.text_1.DOOR"              },
+
+  { "font.input_1",                                    "RocksFontSmall.png"            },
+  { "font.input_1.x",                                  "0"                             },
+  { "font.input_1.y",                                  "210"                           },
+  { "font.input_1.width",                              "14"                            },
+  { "font.input_1.height",                             "14"                            },
+  { "font.input_1.MAIN",                               "RocksFontBig.png"              },
+  { "font.input_1.MAIN.x",                             "0"                             },
+  { "font.input_1.MAIN.y",                             "0"                             },
+  { "font.input_1.MAIN.width",                         "32"                            },
+  { "font.input_1.MAIN.height",                                "32"                            },
+  { "font.input_1.NAMES",                              UNDEFINED_FILENAME              },
+  { "font.input_1.NAMES.clone_from",                   "font.input_1.MAIN"             },
+  { "font.input_1.active",                             "RocksFontSmall.png"            },
+  { "font.input_1.active.x",                           "0"                             },
+  { "font.input_1.active.y",                           "210"                           },
+  { "font.input_1.active.width",                       "14"                            },
+  { "font.input_1.active.height",                      "14"                            },
+  { "font.input_1.active.MAIN",                                "RocksFontBig.png"              },
+  { "font.input_1.active.MAIN.x",                      "0"                             },
+  { "font.input_1.active.MAIN.y",                      "480"                           },
+  { "font.input_1.active.MAIN.width",                  "32"                            },
+  { "font.input_1.active.MAIN.height",                 "32"                            },
+  { "font.input_1.active.NAMES",                       UNDEFINED_FILENAME              },
+  { "font.input_1.active.NAMES.clone_from",            "font.input_1.active.MAIN"      },
+  { "font.input_1.active.SETUP",                       "RocksFontBig.png"              },
+  { "font.input_1.active.SETUP.x",                     "0"                             },
+  { "font.input_1.active.SETUP.y",                     "0"                             },
+  { "font.input_1.active.SETUP.width",                 "32"                            },
+  { "font.input_1.active.SETUP.height",                        "32"                            },
+  { "font.input_2",                                    "RocksFontSmall.png"            },
+  { "font.input_2.x",                                  "0"                             },
+  { "font.input_2.y",                                  "210"                           },
+  { "font.input_2.width",                              "14"                            },
+  { "font.input_2.height",                             "14"                            },
+  { "font.input_2.active",                             "RocksFontSmall.png"            },
+  { "font.input_2.active.x",                           "0"                             },
+  { "font.input_2.active.y",                           "210"                           },
+  { "font.input_2.active.width",                       "14"                            },
+  { "font.input_2.active.height",                      "14"                            },
+
+  { "font.option_off",                                 "RocksFontBig.png"              },
+  { "font.option_off.x",                               "0"                             },
+  { "font.option_off.y",                               "160"                           },
+  { "font.option_off.width",                           "32"                            },
+  { "font.option_off.height",                          "32"                            },
+  { "font.option_off_narrow",                          UNDEFINED_FILENAME              },
+  { "font.option_off_narrow.clone_from",               "font.text_2.LEVELS"            },
+  { "font.option_on",                                  "RocksFontBig.png"              },
+  { "font.option_on.x",                                        "0"                             },
+  { "font.option_on.y",                                        "480"                           },
+  { "font.option_on.width",                            "32"                            },
+  { "font.option_on.height",                           "32"                            },
+  { "font.option_on_narrow",                           UNDEFINED_FILENAME              },
+  { "font.option_on_narrow.clone_from",                        "font.text_4.LEVELS"            },
+
+  { "font.value_1",                                    "RocksFontBig.png"              },
+  { "font.value_1.x",                                  "0"                             },
+  { "font.value_1.y",                                  "480"                           },
+  { "font.value_1.width",                              "32"                            },
+  { "font.value_1.height",                             "32"                            },
+  { "font.value_2",                                    "RocksFontMedium.png"           },
+  { "font.value_2.x",                                  "0"                             },
+  { "font.value_2.y",                                  "480"                           },
+  { "font.value_2.width",                              "16"                            },
+  { "font.value_2.height",                             "32"                            },
+  { "font.value_old",                                  "RocksFontBig.png"              },
+  { "font.value_old.x",                                        "0"                             },
+  { "font.value_old.y",                                        "160"                           },
+  { "font.value_old.width",                            "32"                            },
+  { "font.value_old.height",                           "32"                            },
+  { "font.value_old_narrow",                           UNDEFINED_FILENAME              },
+  { "font.value_old_narrow.clone_from",                        "font.text_2.LEVELS"            },
+  { "font.value_narrow",                               UNDEFINED_FILENAME              },
+  { "font.value_narrow.clone_from",                    "font.text_4.LEVELS"            },
+
+  { "font.level_number",                               "RocksFontSmall.png"            },
+  { "font.level_number.x",                             "0"                             },
+  { "font.level_number.y",                             "350"                           },
+  { "font.level_number.width",                         "10"                            },
+  { "font.level_number.height",                                "14"                            },
+  { "font.level_number.active",                                UNDEFINED_FILENAME              },
+  { "font.level_number.active.clone_from",             "font.level_number"             },
+
+  { "font.tape_recorder",                              "RocksFontSmall.png"            },
+  { "font.tape_recorder.x",                            "0"                             },
+  { "font.tape_recorder.y",                            "280"                           },
+  { "font.tape_recorder.width",                                "11"                            },
+  { "font.tape_recorder.height",                       "14"                            },
+
+  { "font.game_info",                                  "RocksFontEM.png"               },
+  { "font.game_info.xpos",                             "0"                             },
+  { "font.game_info.ypos",                             "0"                             },
+  { "font.game_info.delay",                            "10"                            },
+
+  { "font.info.elements",                              UNDEFINED_FILENAME              },
+  { "font.info.elements.clone_from",                   "font.level_number"             },
+
+  { "font.info.levelset",                              UNDEFINED_FILENAME              },
+  { "font.info.levelset.clone_from",                   "font.level_number"             },
+
+  { "font.main.network_players",                       UNDEFINED_FILENAME              },
+  { "font.main.network_players.clone_from",            "font.level_number"             },
+
+  { "editor.element_border",                           "RocksMore.png"                 },
+  { "editor.element_border.xpos",                      "0"                             },
+  { "editor.element_border.ypos",                      "2"                             },
+  { "editor.element_border.border_size",               "8"                             },
+
+  { "editor.element_border_input",                     "RocksMore.png"                 },
+  { "editor.element_border_input.xpos",                        "10"                            },
+  { "editor.element_border_input.ypos",                        "7"                             },
+  { "editor.element_border_input.border_size",         "4"                             },
+
+  { "editor.counter.down",                             "RocksDoor.png"                 },
+  { "editor.counter.down.x",                           "302"                           },
+  { "editor.counter.down.y",                           "60"                            },
+  { "editor.counter.down.width",                       "20"                            },
+  { "editor.counter.down.height",                      "20"                            },
+  { "editor.counter.down.pressed_xoffset",             "-100"                          },
+
+  { "editor.counter.up",                               "RocksDoor.png"                 },
+  { "editor.counter.up.x",                             "378"                           },
+  { "editor.counter.up.y",                             "60"                            },
+  { "editor.counter.up.width",                         "20"                            },
+  { "editor.counter.up.height",                                "20"                            },
+  { "editor.counter.up.pressed_xoffset",               "-100"                          },
+
+  { "editor.counter.input",                            "RocksDoor.png"                 },
+  { "editor.counter.input.x",                          "324"                           },
+  { "editor.counter.input.y",                          "60"                            },
+  { "editor.counter.input.width",                      "52"                            },
+  { "editor.counter.input.height",                     "20"                            },
+  { "editor.counter.input.active_xoffset",             "-100"                          },
+  { "editor.counter.input.border_size",                        "3"                             },
+
+  { "editor.selectbox.input",                          "RocksDoor.png"                 },
+  { "editor.selectbox.input.x",                                "324"                           },
+  { "editor.selectbox.input.y",                                "82"                            },
+  { "editor.selectbox.input.width",                    "52"                            },
+  { "editor.selectbox.input.height",                   "20"                            },
+  { "editor.selectbox.input.active_xoffset",           "-100"                          },
+  { "editor.selectbox.input.border_size",              "3"                             },
+
+  { "editor.selectbox.button",                         UNDEFINED_FILENAME              },
+  { "editor.selectbox.button.width",                   "14"                            },
+
+  { "editor.checkbox",                                 "RocksDoor.png"                 },
+  { "editor.checkbox.x",                               "302"                           },
+  { "editor.checkbox.y",                               "82"                            },
+  { "editor.checkbox.width",                           "20"                            },
+  { "editor.checkbox.height",                          "20"                            },
+  { "editor.checkbox.pressed_xoffset",                 "-100"                          },
+  { "editor.checkbox.active_xoffset",                  "76"                            },
+
+  { "editor.radiobutton",                              "RocksDoor.png"                 },
+  { "editor.radiobutton.x",                            "302"                           },
+  { "editor.radiobutton.y",                            "104"                           },
+  { "editor.radiobutton.width",                                "20"                            },
+  { "editor.radiobutton.height",                       "20"                            },
+  { "editor.radiobutton.pressed_xoffset",              "-100"                          },
+  { "editor.radiobutton.active_xoffset",               "76"                            },
+
+  { "editor.stickybutton",                             "RocksDoor.png"                 },
+  { "editor.stickybutton.x",                           "302"                           },
+  { "editor.stickybutton.y",                           "126"                           },
+  { "editor.stickybutton.width",                       "20"                            },
+  { "editor.stickybutton.height",                      "20"                            },
+  { "editor.stickybutton.pressed_xoffset",             "-100"                          },
+  { "editor.stickybutton.active_xoffset",              "76"                            },
+
+  { "editor.tabbutton",                                        "RocksDoor.png"                 },
+  { "editor.tabbutton.x",                              "324"                           },
+  { "editor.tabbutton.y",                              "104"                           },
+  { "editor.tabbutton.width",                          "52"                            },
+  { "editor.tabbutton.height",                         "20"                            },
+  { "editor.tabbutton.pressed_xoffset",                        "-100"                          },
+  { "editor.tabbutton.active_yoffset",                 "22"                            },
+  { "editor.tabbutton.border_size",                    "3"                             },
+  { "editor.tabbutton.draw_xoffset",                   "2"                             },
+
+  { "editor.textbutton",                               "RocksDoor.png"                 },
+  { "editor.textbutton.x",                             "324"                           },
+  { "editor.textbutton.y",                             "148"                           },
+  { "editor.textbutton.width",                         "52"                            },
+  { "editor.textbutton.height",                                "20"                            },
+  { "editor.textbutton.pressed_xoffset",               "-100"                          },
+  { "editor.textbutton.border_size",                   "3"                             },
+  { "editor.textbutton.draw_xoffset",                  "2"                             },
+
+  { "editor.input.text",                               "RocksDoor.png"                 },
+  { "editor.input.text.x",                             "324"                           },
+  { "editor.input.text.y",                             "60"                            },
+  { "editor.input.text.width",                         "52"                            },
+  { "editor.input.text.height",                                "20"                            },
+  { "editor.input.text.active_xoffset",                        "-100"                          },
+  { "editor.input.text.border_size",                   "3"                             },
+
+  { "editor.input.textarea",                           "RocksDoor.png"                 },
+  { "editor.input.textarea.x",                         "324"                           },
+  { "editor.input.textarea.y",                         "60"                            },
+  { "editor.input.textarea.width",                     "52"                            },
+  { "editor.input.textarea.height",                    "20"                            },
+  { "editor.input.textarea.active_xoffset",            "-100"                          },
+  { "editor.input.textarea.border_size",               "3"                             },
+
+  { "editor.cascade_list",                             "RocksMore.png"                 },
+  { "editor.cascade_list.xpos",                                "9"                             },
+  { "editor.cascade_list.ypos",                                "8"                             },
+  { "editor.cascade_list.frames",                      "1"                             },
+  { "editor.cascade_list.active",                      "RocksMore.png"                 },
+  { "editor.cascade_list.active.xpos",                 "10"                            },
+  { "editor.cascade_list.active.ypos",                 "8"                             },
+  { "editor.cascade_list.active.frames",               "1"                             },
+
+  { "editor.palette.button",                           "RocksDoor.png"                 },
+  { "editor.palette.button.x",                         "525"                           },
+  { "editor.palette.button.y",                         "30"                            },
+  { "editor.palette.button.width",                     "20"                            },
+  { "editor.palette.button.height",                    "20"                            },
+  { "editor.palette.button.pressed_xoffset",           "-20"                           },
+
+  { "editor.palette.scroll_up",                                "RocksDoor.png"                 },
+  { "editor.palette.scroll_up.x",                      "750"                           },
+  { "editor.palette.scroll_up.y",                      "0"                             },
+  { "editor.palette.scroll_up.width",                  "10"                            },
+  { "editor.palette.scroll_up.height",                 "10"                            },
+  { "editor.palette.scroll_up.pressed_xoffset",                "-10"                           },
+
+  { "editor.palette.scroll_down",                      "RocksDoor.png"                 },
+  { "editor.palette.scroll_down.x",                    "750"                           },
+  { "editor.palette.scroll_down.y",                    "10"                            },
+  { "editor.palette.scroll_down.width",                        "10"                            },
+  { "editor.palette.scroll_down.height",               "10"                            },
+  { "editor.palette.scroll_down.pressed_xoffset",      "-10"                           },
+
+  { "editor.palette.scrollbar",                                "RocksDoor.png"                 },
+  { "editor.palette.scrollbar.x",                      "750"                           },
+  { "editor.palette.scrollbar.y",                      "20"                            },
+  { "editor.palette.scrollbar.width",                  "10"                            },
+  { "editor.palette.scrollbar.height",                 "10"                            },
+  { "editor.palette.scrollbar.pressed_xoffset",                "-10"                           },
+  { "editor.palette.scrollbar.border_size",            "3"                             },
+
+  { "editor.playfield.scroll_up",                      "RocksDoor.png"                 },
+  { "editor.playfield.scroll_up.x",                    "724"                           },
+  { "editor.playfield.scroll_up.y",                    "0"                             },
+  { "editor.playfield.scroll_up.width",                        "16"                            },
+  { "editor.playfield.scroll_up.height",               "16"                            },
+  { "editor.playfield.scroll_up.pressed_xoffset",      "-16"                           },
+
+  { "editor.playfield.scroll_down",                    "RocksDoor.png"                 },
+  { "editor.playfield.scroll_down.x",                  "724"                           },
+  { "editor.playfield.scroll_down.y",                  "16"                            },
+  { "editor.playfield.scroll_down.width",              "16"                            },
+  { "editor.playfield.scroll_down.height",             "16"                            },
+  { "editor.playfield.scroll_down.pressed_xoffset",    "-16"                           },
+
+  { "editor.playfield.scroll_left",                    "RocksDoor.png"                 },
+  { "editor.playfield.scroll_left.x",                  "724"                           },
+  { "editor.playfield.scroll_left.y",                  "32"                            },
+  { "editor.playfield.scroll_left.width",              "16"                            },
+  { "editor.playfield.scroll_left.height",             "16"                            },
+  { "editor.playfield.scroll_left.pressed_xoffset",    "-16"                           },
+
+  { "editor.playfield.scroll_right",                   "RocksDoor.png"                 },
+  { "editor.playfield.scroll_right.x",                 "724"                           },
+  { "editor.playfield.scroll_right.y",                 "48"                            },
+  { "editor.playfield.scroll_right.width",             "16"                            },
+  { "editor.playfield.scroll_right.height",            "16"                            },
+  { "editor.playfield.scroll_right.pressed_xoffset",   "-16"                           },
+
+  { "editor.playfield.scrollbar",                      "RocksDoor.png"                 },
+  { "editor.playfield.scrollbar.x",                    "724"                           },
+  { "editor.playfield.scrollbar.y",                    "64"                            },
+  { "editor.playfield.scrollbar.width",                        "16"                            },
+  { "editor.playfield.scrollbar.height",               "16"                            },
+  { "editor.playfield.scrollbar.pressed_xoffset",      "-16"                           },
+  { "editor.playfield.scrollbar.border_size",          "3"                             },
+
+  { "gfx.editor.button.prev_level",                    "RocksDoor.png"                 },
+  { "gfx.editor.button.prev_level.x",                  "724"                           },
+  { "gfx.editor.button.prev_level.y",                  "32"                            },
+  { "gfx.editor.button.prev_level.width",              "16"                            },
+  { "gfx.editor.button.prev_level.height",             "16"                            },
+  { "gfx.editor.button.prev_level.pressed_xoffset",    "-16"                           },
+
+  { "gfx.editor.button.next_level",                    "RocksDoor.png"                 },
+  { "gfx.editor.button.next_level.x",                  "724"                           },
+  { "gfx.editor.button.next_level.y",                  "48"                            },
+  { "gfx.editor.button.next_level.width",              "16"                            },
+  { "gfx.editor.button.next_level.height",             "16"                            },
+  { "gfx.editor.button.next_level.pressed_xoffset",    "-16"                           },
+
+  { "gfx.editor.button.properties",                    "RocksDoor2.png"                },
+  { "gfx.editor.button.properties.x",                  "105"                           },
+  { "gfx.editor.button.properties.y",                  "0"                             },
+  { "gfx.editor.button.properties.width",              "90"                            },
+  { "gfx.editor.button.properties.height",             "20"                            },
+  { "gfx.editor.button.properties.pressed_xoffset",    "-100"                          },
+
+  { "gfx.editor.button.element_left",                  "RocksDoor2.png"                },
+  { "gfx.editor.button.element_left.x",                        "368"                           },
+  { "gfx.editor.button.element_left.y",                        "48"                            },
+  { "gfx.editor.button.element_left.width",            "16"                            },
+  { "gfx.editor.button.element_left.height",           "16"                            },
+  { "gfx.editor.button.element_left.pressed_xoffset",  "0"                             },
+
+  { "gfx.editor.button.element_middle",                        "RocksDoor2.png"                },
+  { "gfx.editor.button.element_middle.x",              "368"                           },
+  { "gfx.editor.button.element_middle.y",              "48"                            },
+  { "gfx.editor.button.element_middle.width",          "16"                            },
+  { "gfx.editor.button.element_middle.height",         "16"                            },
+  { "gfx.editor.button.element_middle.pressed_xoffset",        "0"                             },
+
+  { "gfx.editor.button.element_right",                 "RocksDoor2.png"                },
+  { "gfx.editor.button.element_right.x",               "368"                           },
+  { "gfx.editor.button.element_right.y",               "48"                            },
+  { "gfx.editor.button.element_right.width",           "16"                            },
+  { "gfx.editor.button.element_right.height",          "16"                            },
+  { "gfx.editor.button.element_right.pressed_xoffset", "0"                             },
+
+  { "gfx.editor.button.palette",                       UNDEFINED_FILENAME              },
+
+  { "editor.no_toolbox_button",                                "RocksDoor.png"                 },
+  { "editor.no_toolbox_button.x",                      "506"                           },
+  { "editor.no_toolbox_button.y",                      "286"                           },
+  { "editor.no_toolbox_button.width",                  "22"                            },
+  { "editor.no_toolbox_button.height",                 "22"                            },
+
+  { "gfx.editor.button.draw_single",                   "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_single.x",                 "706"                           },
+  { "gfx.editor.button.draw_single.y",                 "242"                           },
+  { "gfx.editor.button.draw_single.width",             "22"                            },
+  { "gfx.editor.button.draw_single.height",            "22"                            },
+  { "gfx.editor.button.draw_single.pressed_xoffset",   "-100"                          },
+  { "gfx.editor.button.draw_single.active_yoffset",    "-94"                           },
+
+  { "gfx.editor.button.draw_connected",                        "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_connected.x",              "728"                           },
+  { "gfx.editor.button.draw_connected.y",              "242"                           },
+  { "gfx.editor.button.draw_connected.width",          "22"                            },
+  { "gfx.editor.button.draw_connected.height",         "22"                            },
+  { "gfx.editor.button.draw_connected.pressed_xoffset",        "-100"                          },
+  { "gfx.editor.button.draw_connected.active_yoffset",  "-94"                          },
+
+  { "gfx.editor.button.draw_line",                     "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_line.x",                   "750"                           },
+  { "gfx.editor.button.draw_line.y",                   "242"                           },
+  { "gfx.editor.button.draw_line.width",               "22"                            },
+  { "gfx.editor.button.draw_line.height",              "22"                            },
+  { "gfx.editor.button.draw_line.pressed_xoffset",     "-100"                          },
+  { "gfx.editor.button.draw_line.active_yoffset",      "-94"                           },
+
+  { "gfx.editor.button.draw_arc",                      "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_arc.x",                    "772"                           },
+  { "gfx.editor.button.draw_arc.y",                    "242"                           },
+  { "gfx.editor.button.draw_arc.width",                        "22"                            },
+  { "gfx.editor.button.draw_arc.height",               "22"                            },
+  { "gfx.editor.button.draw_arc.pressed_xoffset",      "-100"                          },
+  { "gfx.editor.button.draw_arc.active_yoffset",       "-94"                           },
+
+  { "gfx.editor.button.draw_rectangle",                        "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_rectangle.x",              "706"                           },
+  { "gfx.editor.button.draw_rectangle.y",              "264"                           },
+  { "gfx.editor.button.draw_rectangle.width",          "22"                            },
+  { "gfx.editor.button.draw_rectangle.height",         "22"                            },
+  { "gfx.editor.button.draw_rectangle.pressed_xoffset",        "-100"                          },
+  { "gfx.editor.button.draw_rectangle.active_yoffset", "-94"                           },
+
+  { "gfx.editor.button.draw_filled_box",               "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_filled_box.x",             "728"                           },
+  { "gfx.editor.button.draw_filled_box.y",             "264"                           },
+  { "gfx.editor.button.draw_filled_box.width",         "22"                            },
+  { "gfx.editor.button.draw_filled_box.height",                "22"                            },
+  { "gfx.editor.button.draw_filled_box.pressed_xoffset","-100"                         },
+  { "gfx.editor.button.draw_filled_box.active_yoffset",        "-94"                           },
+
+  { "gfx.editor.button.rotate_up",                     "RocksDoor.png"                 },
+  { "gfx.editor.button.rotate_up.x",                   "750"                           },
+  { "gfx.editor.button.rotate_up.y",                   "264"                           },
+  { "gfx.editor.button.rotate_up.width",               "22"                            },
+  { "gfx.editor.button.rotate_up.height",              "22"                            },
+  { "gfx.editor.button.rotate_up.pressed_xoffset",     "-100"                          },
+  { "gfx.editor.button.rotate_up.active_yoffset",      "-94"                           },
+
+  { "gfx.editor.button.draw_text",                     "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_text.x",                   "772"                           },
+  { "gfx.editor.button.draw_text.y",                   "264"                           },
+  { "gfx.editor.button.draw_text.width",               "22"                            },
+  { "gfx.editor.button.draw_text.height",              "22"                            },
+  { "gfx.editor.button.draw_text.pressed_xoffset",     "-100"                          },
+  { "gfx.editor.button.draw_text.active_yoffset",      "-94"                           },
+
+  { "gfx.editor.button.flood_fill",                    "RocksDoor.png"                 },
+  { "gfx.editor.button.flood_fill.x",                  "706"                           },
+  { "gfx.editor.button.flood_fill.y",                  "286"                           },
+  { "gfx.editor.button.flood_fill.width",              "22"                            },
+  { "gfx.editor.button.flood_fill.height",             "22"                            },
+  { "gfx.editor.button.flood_fill.pressed_xoffset",    "-100"                          },
+  { "gfx.editor.button.flood_fill.active_yoffset",     "-94"                           },
+
+  { "gfx.editor.button.rotate_left",                   "RocksDoor.png"                 },
+  { "gfx.editor.button.rotate_left.x",                 "728"                           },
+  { "gfx.editor.button.rotate_left.y",                 "286"                           },
+  { "gfx.editor.button.rotate_left.width",             "22"                            },
+  { "gfx.editor.button.rotate_left.height",            "22"                            },
+  { "gfx.editor.button.rotate_left.pressed_xoffset",   "-100"                          },
+  { "gfx.editor.button.rotate_left.active_yoffset",    "-94"                           },
+
+  { "gfx.editor.button.zoom_level",                    "RocksDoor2.png"                },
+  { "gfx.editor.button.zoom_level.x",                  "350"                           },
+  { "gfx.editor.button.zoom_level.y",                  "22"                            },
+  { "gfx.editor.button.zoom_level.width",              "22"                            },
+  { "gfx.editor.button.zoom_level.height",             "22"                            },
+  { "gfx.editor.button.zoom_level.pressed_xoffset",    "-100"                          },
+  { "gfx.editor.button.zoom_level.active_yoffset",     "-22"                           },
+
+  { "gfx.editor.button.rotate_right",                  "RocksDoor.png"                 },
+  { "gfx.editor.button.rotate_right.x",                        "772"                           },
+  { "gfx.editor.button.rotate_right.y",                        "286"                           },
+  { "gfx.editor.button.rotate_right.width",            "22"                            },
+  { "gfx.editor.button.rotate_right.height",           "22"                            },
+  { "gfx.editor.button.rotate_right.pressed_xoffset",  "-100"                          },
+  { "gfx.editor.button.rotate_right.active_yoffset",   "-94"                           },
+
+  { "gfx.editor.button.draw_random",                   "RocksDoor.png"                 },
+  { "gfx.editor.button.draw_random.x",                 "706"                           },
+  { "gfx.editor.button.draw_random.y",                 "308"                           },
+  { "gfx.editor.button.draw_random.width",             "22"                            },
+  { "gfx.editor.button.draw_random.height",            "22"                            },
+  { "gfx.editor.button.draw_random.pressed_xoffset",   "-100"                          },
+  { "gfx.editor.button.draw_random.active_yoffset",    "-94"                           },
+
+  { "gfx.editor.button.grab_brush",                    "RocksDoor.png"                 },
+  { "gfx.editor.button.grab_brush.x",                  "728"                           },
+  { "gfx.editor.button.grab_brush.y",                  "308"                           },
+  { "gfx.editor.button.grab_brush.width",              "22"                            },
+  { "gfx.editor.button.grab_brush.height",             "22"                            },
+  { "gfx.editor.button.grab_brush.pressed_xoffset",    "-100"                          },
+  { "gfx.editor.button.grab_brush.active_yoffset",     "-94"                           },
+
+  { "gfx.editor.button.rotate_down",                   "RocksDoor.png"                 },
+  { "gfx.editor.button.rotate_down.x",                 "750"                           },
+  { "gfx.editor.button.rotate_down.y",                 "308"                           },
+  { "gfx.editor.button.rotate_down.width",             "22"                            },
+  { "gfx.editor.button.rotate_down.height",            "22"                            },
+  { "gfx.editor.button.rotate_down.pressed_xoffset",   "-100"                          },
+  { "gfx.editor.button.rotate_down.active_yoffset",    "-94"                           },
+
+  { "gfx.editor.button.pick_element",                  "RocksDoor.png"                 },
+  { "gfx.editor.button.pick_element.x",                        "772"                           },
+  { "gfx.editor.button.pick_element.y",                        "308"                           },
+  { "gfx.editor.button.pick_element.width",            "22"                            },
+  { "gfx.editor.button.pick_element.height",           "22"                            },
+  { "gfx.editor.button.pick_element.pressed_xoffset",  "-100"                          },
+  { "gfx.editor.button.pick_element.active_yoffset",   "-94"                           },
+
+  { "gfx.editor.button.ce_copy_from",                  "RocksDoor.png"                 },
+  { "gfx.editor.button.ce_copy_from.x",                        "528"                           },
+  { "gfx.editor.button.ce_copy_from.y",                        "330"                           },
+  { "gfx.editor.button.ce_copy_from.width",            "22"                            },
+  { "gfx.editor.button.ce_copy_from.height",           "22"                            },
+  { "gfx.editor.button.ce_copy_from.pressed_xoffset",  "-100"                          },
+  { "gfx.editor.button.ce_copy_from.active_yoffset",   "-22"                           },
+
+  { "gfx.editor.button.ce_copy_to",                    "RocksDoor.png"                 },
+  { "gfx.editor.button.ce_copy_to.x",                  "550"                           },
+  { "gfx.editor.button.ce_copy_to.y",                  "330"                           },
+  { "gfx.editor.button.ce_copy_to.width",              "22"                            },
+  { "gfx.editor.button.ce_copy_to.height",             "22"                            },
+  { "gfx.editor.button.ce_copy_to.pressed_xoffset",    "-100"                          },
+  { "gfx.editor.button.ce_copy_to.active_yoffset",     "-22"                           },
+
+  { "gfx.editor.button.ce_swap",                       "RocksDoor.png"                 },
+  { "gfx.editor.button.ce_swap.x",                     "572"                           },
+  { "gfx.editor.button.ce_swap.y",                     "330"                           },
+  { "gfx.editor.button.ce_swap.width",                 "22"                            },
+  { "gfx.editor.button.ce_swap.height",                        "22"                            },
+  { "gfx.editor.button.ce_swap.pressed_xoffset",       "-100"                          },
+  { "gfx.editor.button.ce_swap.active_yoffset",                "-22"                           },
+
+  { "gfx.editor.button.ce_copy",                       "RocksDoor.png"                 },
+  { "gfx.editor.button.ce_copy.x",                     "550"                           },
+  { "gfx.editor.button.ce_copy.y",                     "286"                           },
+  { "gfx.editor.button.ce_copy.width",                 "22"                            },
+  { "gfx.editor.button.ce_copy.height",                        "22"                            },
+  { "gfx.editor.button.ce_copy.pressed_xoffset",       "-100"                          },
+
+  { "gfx.editor.button.ce_paste",                      "RocksDoor.png"                 },
+  { "gfx.editor.button.ce_paste.x",                    "572"                           },
+  { "gfx.editor.button.ce_paste.y",                    "286"                           },
+  { "gfx.editor.button.ce_paste.width",                        "22"                            },
+  { "gfx.editor.button.ce_paste.height",               "22"                            },
+  { "gfx.editor.button.ce_paste.pressed_xoffset",      "-100"                          },
+
+  { "gfx.editor.button.cp_copy",                       "RocksDoor.png"                 },
+  { "gfx.editor.button.cp_copy.x",                     "525"                           },
+  { "gfx.editor.button.cp_copy.y",                     "50"                            },
+  { "gfx.editor.button.cp_copy.width",                 "20"                            },
+  { "gfx.editor.button.cp_copy.height",                        "20"                            },
+  { "gfx.editor.button.cp_copy.pressed_xoffset",       "-20"                           },
+
+  { "gfx.editor.button.cp_paste",                      "RocksDoor.png"                 },
+  { "gfx.editor.button.cp_paste.x",                    "525"                           },
+  { "gfx.editor.button.cp_paste.y",                    "70"                            },
+  { "gfx.editor.button.cp_paste.width",                        "20"                            },
+  { "gfx.editor.button.cp_paste.height",               "20"                            },
+  { "gfx.editor.button.cp_paste.pressed_xoffset",      "-20"                           },
+
+  { "gfx.editor.button.undo",                          "RocksDoor.png"                 },
+  { "gfx.editor.button.undo.x",                                "705"                           },
+  { "gfx.editor.button.undo.y",                                "335"                           },
+  { "gfx.editor.button.undo.width",                    "30"                            },
+  { "gfx.editor.button.undo.height",                   "20"                            },
+  { "gfx.editor.button.undo.pressed_xoffset",          "-100"                          },
+
+  { "gfx.editor.button.conf",                          "RocksDoor.png"                 },
+  { "gfx.editor.button.conf.x",                                "735"                           },
+  { "gfx.editor.button.conf.y",                                "335"                           },
+  { "gfx.editor.button.conf.width",                    "30"                            },
+  { "gfx.editor.button.conf.height",                   "20"                            },
+  { "gfx.editor.button.conf.pressed_xoffset",          "-100"                          },
+
+  { "gfx.editor.button.save",                          "RocksDoor.png"                 },
+  { "gfx.editor.button.save.x",                                "765"                           },
+  { "gfx.editor.button.save.y",                                "335"                           },
+  { "gfx.editor.button.save.width",                    "30"                            },
+  { "gfx.editor.button.save.height",                   "20"                            },
+  { "gfx.editor.button.save.pressed_xoffset",          "-100"                          },
+
+  { "gfx.editor.button.clear",                         "RocksDoor.png"                 },
+  { "gfx.editor.button.clear.x",                       "705"                           },
+  { "gfx.editor.button.clear.y",                       "355"                           },
+  { "gfx.editor.button.clear.width",                   "30"                            },
+  { "gfx.editor.button.clear.height",                  "20"                            },
+  { "gfx.editor.button.clear.pressed_xoffset",         "-100"                          },
+
+  { "gfx.editor.button.test",                          "RocksDoor.png"                 },
+  { "gfx.editor.button.test.x",                                "735"                           },
+  { "gfx.editor.button.test.y",                                "355"                           },
+  { "gfx.editor.button.test.width",                    "30"                            },
+  { "gfx.editor.button.test.height",                   "20"                            },
+  { "gfx.editor.button.test.pressed_xoffset",          "-100"                          },
+
+  { "gfx.editor.button.exit",                          "RocksDoor.png"                 },
+  { "gfx.editor.button.exit.x",                                "765"                           },
+  { "gfx.editor.button.exit.y",                                "355"                           },
+  { "gfx.editor.button.exit.width",                    "30"                            },
+  { "gfx.editor.button.exit.height",                   "20"                            },
+  { "gfx.editor.button.exit.pressed_xoffset",          "-100"                          },
+
+  { "gfx.editor.input.level_number",                   "RocksDoor.png"                 },
+  { "gfx.editor.input.level_number.x",                 "529"                           },
+  { "gfx.editor.input.level_number.y",                 "5"                             },
+  { "gfx.editor.input.level_number.width",             "42"                            },
+  { "gfx.editor.input.level_number.height",            "16"                            },
+  { "gfx.editor.input.level_number.border_size",       "1"                             },
+
+  { "setup.input.text",                                        "RocksSP.png"                   },
+  { "setup.input.text.x",                              "0"                             },
+  { "setup.input.text.y",                              "0"                             },
+  { "setup.input.text.width",                          "32"                            },
+  { "setup.input.text.height",                         "32"                            },
+  { "setup.input.text.active_xoffset",                 "0"                             },
+  { "setup.input.text.border_size",                    "0"                             },
+
+  { "global.border",                                   "RocksScreen.png"               },
+  { "global.border.MAIN",                              UNDEFINED_FILENAME              },
+  { "global.border.SCORES",                            UNDEFINED_FILENAME              },
+  { "global.border.EDITOR",                            UNDEFINED_FILENAME              },
+  { "global.border.PLAYING",                           UNDEFINED_FILENAME              },
+
+  { "global.door",                                     "RocksDoor.png"                 },
+
+  { "global.busy_initial",                             "RocksBusy.png"                 },
+  { "global.busy_initial.x",                           "0"                             },
+  { "global.busy_initial.y",                           "0"                             },
+  { "global.busy_initial.width",                       "32"                            },
+  { "global.busy_initial.height",                      "32"                            },
+  { "global.busy_initial.frames",                      "28"                            },
+  { "global.busy_initial.frames_per_line",             "7"                             },
+  { "global.busy_initial.delay",                       "2"                             },
+  { "global.busy",                                     "RocksBusy.png"                 },
+  { "global.busy.x",                                   "0"                             },
+  { "global.busy.y",                                   "0"                             },
+  { "global.busy.width",                               "32"                            },
+  { "global.busy.height",                              "32"                            },
+  { "global.busy.frames",                              "28"                            },
+  { "global.busy.frames_per_line",                     "7"                             },
+  { "global.busy.delay",                               "2"                             },
+  { "global.busy_playfield",                           "RocksBusy.png"                 },
+  { "global.busy_playfield.x",                         "0"                             },
+  { "global.busy_playfield.y",                         "0"                             },
+  { "global.busy_playfield.width",                     "32"                            },
+  { "global.busy_playfield.height",                    "32"                            },
+  { "global.busy_playfield.frames",                    "28"                            },
+  { "global.busy_playfield.frames_per_line",           "7"                             },
+  { "global.busy_playfield.delay",                     "2"                             },
+
+  { "global.tile_cursor",                              "RocksMore.png"                 },
+  { "global.tile_cursor.xpos",                         "10"                            },
+  { "global.tile_cursor.ypos",                         "7"                             },
+  { "global.tile_cursor.frames",                       "1"                             },
+
+  { "background",                                      UNDEFINED_FILENAME              },
+  { "background.LOADING_INITIAL",                      UNDEFINED_FILENAME              },
+  { "background.LOADING",                              UNDEFINED_FILENAME              },
+  { "background.TITLE_INITIAL",                                UNDEFINED_FILENAME              },
+  { "background.TITLE",                                        UNDEFINED_FILENAME              },
+  { "background.MAIN",                                 UNDEFINED_FILENAME              },
+  { "background.NAMES",                                        UNDEFINED_FILENAME              },
+  { "background.LEVELS",                               UNDEFINED_FILENAME              },
+  { "background.LEVELNR",                              UNDEFINED_FILENAME              },
+  { "background.SCORES",                               UNDEFINED_FILENAME              },
+  { "background.SCOREINFO",                            UNDEFINED_FILENAME              },
+  { "background.EDITOR",                               UNDEFINED_FILENAME              },
+  { "background.INFO",                                 UNDEFINED_FILENAME              },
+  { "background.INFO[ELEMENTS]",                       UNDEFINED_FILENAME              },
+  { "background.INFO[MUSIC]",                          UNDEFINED_FILENAME              },
+  { "background.INFO[CREDITS]",                                UNDEFINED_FILENAME              },
+  { "background.INFO[PROGRAM]",                                UNDEFINED_FILENAME              },
+  { "background.INFO[VERSION]",                                UNDEFINED_FILENAME              },
+  { "background.INFO[LEVELSET]",                       UNDEFINED_FILENAME              },
+  { "background.SETUP",                                        UNDEFINED_FILENAME              },
+  { "background.PLAYING",                              UNDEFINED_FILENAME              },
+  { "background.DOOR",                                 UNDEFINED_FILENAME              },
+  { "background.TAPE",                                 "RocksDoor.png"                 },
+  { "background.TAPE.x",                               "200"                           },
+  { "background.TAPE.y",                               "280"                           },
+  { "background.TAPE.width",                           "100"                           },
+  { "background.TAPE.height",                          "100"                           },
+  { "background.PANEL",                                        "RocksDoor.png"                 },
+  { "background.PANEL.x",                              "400"                           },
+  { "background.PANEL.y",                              "0"                             },
+  { "background.PANEL.width",                          "100"                           },
+  { "background.PANEL.height",                         "280"                           },
+  { "background.PALETTE",                              "RocksDoor.png"                 },
+  { "background.PALETTE.x",                            "500"                           },
+  { "background.PALETTE.y",                            "0"                             },
+  { "background.PALETTE.width",                                "100"                           },
+  { "background.PALETTE.height",                       "280"                           },
+  { "background.TOOLBOX",                              "RocksDoor.png"                 },
+  { "background.TOOLBOX.x",                            "700"                           },
+  { "background.TOOLBOX.y",                            "236"                           },
+  { "background.TOOLBOX.width",                                "100"                           },
+  { "background.TOOLBOX.height",                       "144"                           },
+
+  { "background.titlescreen_initial_1",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_2",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_3",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_4",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_5",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_1",                                UNDEFINED_FILENAME              },
+  { "background.titlescreen_2",                                UNDEFINED_FILENAME              },
+  { "background.titlescreen_3",                                UNDEFINED_FILENAME              },
+  { "background.titlescreen_4",                                UNDEFINED_FILENAME              },
+  { "background.titlescreen_5",                                UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_1",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_2",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_3",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_4",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_5",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_1",                       UNDEFINED_FILENAME              },
+  { "background.titlemessage_2",                       UNDEFINED_FILENAME              },
+  { "background.titlemessage_3",                       UNDEFINED_FILENAME              },
+  { "background.titlemessage_4",                       UNDEFINED_FILENAME              },
+  { "background.titlemessage_5",                       UNDEFINED_FILENAME              },
+
+  { "background.envelope_1",                           "RocksScreen.png"               },
+  { "background.envelope_1.x",                         "0"                             },
+  { "background.envelope_1.y",                         "0"                             },
+  { "background.envelope_1.width",                     "560"                           },
+  { "background.envelope_1.height",                    "560"                           },
+  { "background.envelope_1.anim_mode",                 "default"                       },
+  { "background.envelope_1.draw_masked",               "false"                         },
+  { "background.envelope_2",                           "RocksScreen.png"               },
+  { "background.envelope_2.x",                         "0"                             },
+  { "background.envelope_2.y",                         "0"                             },
+  { "background.envelope_2.width",                     "560"                           },
+  { "background.envelope_2.height",                    "560"                           },
+  { "background.envelope_2.anim_mode",                 "default"                       },
+  { "background.envelope_2.draw_masked",               "false"                         },
+  { "background.envelope_3",                           "RocksScreen.png"               },
+  { "background.envelope_3.x",                         "0"                             },
+  { "background.envelope_3.y",                         "0"                             },
+  { "background.envelope_3.width",                     "560"                           },
+  { "background.envelope_3.height",                    "560"                           },
+  { "background.envelope_3.anim_mode",                 "default"                       },
+  { "background.envelope_3.draw_masked",               "false"                         },
+  { "background.envelope_4",                           "RocksScreen.png"               },
+  { "background.envelope_4.x",                         "0"                             },
+  { "background.envelope_4.y",                         "0"                             },
+  { "background.envelope_4.width",                     "560"                           },
+  { "background.envelope_4.height",                    "560"                           },
+  { "background.envelope_4.anim_mode",                 "default"                       },
+  { "background.envelope_4.draw_masked",               "false"                         },
+
+  { "background.request",                              "RocksScreen.png"               },
+  { "background.request.x",                            "562"                           },
+  { "background.request.y",                            "56"                            },
+  { "background.request.width",                                "108"                           },
+  { "background.request.height",                       "288"                           },
+  { "background.request.anim_mode",                    "default"                       },
+  { "background.request.draw_masked",                  "false"                         },
+
+  { "titlescreen_initial_1",                           UNDEFINED_FILENAME              },
+  { "titlescreen_initial_2",                           UNDEFINED_FILENAME              },
+  { "titlescreen_initial_3",                           UNDEFINED_FILENAME              },
+  { "titlescreen_initial_4",                           UNDEFINED_FILENAME              },
+  { "titlescreen_initial_5",                           UNDEFINED_FILENAME              },
+  { "titlescreen_1",                                   UNDEFINED_FILENAME              },
+  { "titlescreen_2",                                   UNDEFINED_FILENAME              },
+  { "titlescreen_3",                                   UNDEFINED_FILENAME              },
+  { "titlescreen_4",                                   UNDEFINED_FILENAME              },
+  { "titlescreen_5",                                   UNDEFINED_FILENAME              },
+
+  { "gfx.door_1.part_1",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_1.x",                             "0"                             },
+  { "gfx.door_1.part_1.y",                             "0"                             },
+  { "gfx.door_1.part_1.width",                         "100"                           },
+  { "gfx.door_1.part_1.height",                                "77"                            },
+  { "gfx.door_1.part_1.frames",                                "1"                             },
+  { "gfx.door_1.part_2",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_2.x",                             "0"                             },
+  { "gfx.door_1.part_2.y",                             "77"                            },
+  { "gfx.door_1.part_2.width",                         "100"                           },
+  { "gfx.door_1.part_2.height",                                "63"                            },
+  { "gfx.door_1.part_2.frames",                                "1"                             },
+  { "gfx.door_1.part_3",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_3.x",                             "0"                             },
+  { "gfx.door_1.part_3.y",                             "140"                           },
+  { "gfx.door_1.part_3.width",                         "100"                           },
+  { "gfx.door_1.part_3.height",                                "63"                            },
+  { "gfx.door_1.part_3.frames",                                "1"                             },
+  { "gfx.door_1.part_4",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_4.x",                             "0"                             },
+  { "gfx.door_1.part_4.y",                             "203"                           },
+  { "gfx.door_1.part_4.width",                         "100"                           },
+  { "gfx.door_1.part_4.height",                                "77"                            },
+  { "gfx.door_1.part_4.frames",                                "1"                             },
+  { "gfx.door_1.part_5",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_5.x",                             "100"                           },
+  { "gfx.door_1.part_5.y",                             "0"                             },
+  { "gfx.door_1.part_5.width",                         "100"                           },
+  { "gfx.door_1.part_5.height",                                "77"                            },
+  { "gfx.door_1.part_5.frames",                                "1"                             },
+  { "gfx.door_1.part_6",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_6.x",                             "100"                           },
+  { "gfx.door_1.part_6.y",                             "77"                            },
+  { "gfx.door_1.part_6.width",                         "100"                           },
+  { "gfx.door_1.part_6.height",                                "63"                            },
+  { "gfx.door_1.part_6.frames",                                "1"                             },
+  { "gfx.door_1.part_7",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_7.x",                             "100"                           },
+  { "gfx.door_1.part_7.y",                             "140"                           },
+  { "gfx.door_1.part_7.width",                         "100"                           },
+  { "gfx.door_1.part_7.height",                                "63"                            },
+  { "gfx.door_1.part_7.frames",                                "1"                             },
+  { "gfx.door_1.part_8",                               "RocksDoor.png"                 },
+  { "gfx.door_1.part_8.x",                             "100"                           },
+  { "gfx.door_1.part_8.y",                             "203"                           },
+  { "gfx.door_1.part_8.width",                         "100"                           },
+  { "gfx.door_1.part_8.height",                                "77"                            },
+  { "gfx.door_1.part_8.frames",                                "1"                             },
+
+  { "gfx.door_2.part_1",                               "RocksDoor.png"                 },
+  { "gfx.door_2.part_1.x",                             "0"                             },
+  { "gfx.door_2.part_1.y",                             "280"                           },
+  { "gfx.door_2.part_1.width",                         "100"                           },
+  { "gfx.door_2.part_1.height",                                "50"                            },
+  { "gfx.door_2.part_1.frames",                                "1"                             },
+  { "gfx.door_2.part_2",                               "RocksDoor.png"                 },
+  { "gfx.door_2.part_2.x",                             "0"                             },
+  { "gfx.door_2.part_2.y",                             "330"                           },
+  { "gfx.door_2.part_2.width",                         "100"                           },
+  { "gfx.door_2.part_2.height",                                "50"                            },
+  { "gfx.door_2.part_2.frames",                                "1"                             },
+  { "gfx.door_2.part_3",                               "RocksDoor.png"                 },
+  { "gfx.door_2.part_3.x",                             "100"                           },
+  { "gfx.door_2.part_3.y",                             "280"                           },
+  { "gfx.door_2.part_3.width",                         "100"                           },
+  { "gfx.door_2.part_3.height",                                "50"                            },
+  { "gfx.door_2.part_3.frames",                                "1"                             },
+  { "gfx.door_2.part_4",                               "RocksDoor.png"                 },
+  { "gfx.door_2.part_4.x",                             "100"                           },
+  { "gfx.door_2.part_4.y",                             "330"                           },
+  { "gfx.door_2.part_4.width",                         "100"                           },
+  { "gfx.door_2.part_4.height",                                "50"                            },
+  { "gfx.door_2.part_4.frames",                                "1"                             },
+  { "gfx.door_2.part_5",                               UNDEFINED_FILENAME              },
+  { "gfx.door_2.part_6",                               UNDEFINED_FILENAME              },
+  { "gfx.door_2.part_7",                               UNDEFINED_FILENAME              },
+  { "gfx.door_2.part_8",                               UNDEFINED_FILENAME              },
+
+  { "door_2.top_border_correction",                    "RocksDoor.png"                 },
+  { "door_2.top_border_correction.x",                  "600"                           },
+  { "door_2.top_border_correction.y",                  "0"                             },
+  { "door_2.top_border_correction.width",              "108"                           },
+  { "door_2.top_border_correction.height",             "8"                             },
 
   // the last image entry apparently gets overwritten by very last entry
   // of "image_config[]"; so far this bug could not be found and fixed
-  { "last_image_entry_bug",                    UNDEFINED_FILENAME      },
+  { "last_image_entry_bug",                            UNDEFINED_FILENAME              },
 
 
   // ==========================================================================
@@ -7537,2553 +8732,2648 @@ struct ConfigInfo image_config[] =
 
   // keyword to start parser: "CONFIG_VARS_START" <-- do not change!
 
-  { "[title_initial].fade_mode",               "fade"                  },
-  { "[title_initial].fade_delay",              "500"                   },
-  { "[title_initial].post_delay",              "250"                   },
-  { "[title_initial].auto_delay",              "-1"                    },
-  { "[title_initial].auto_delay_unit",         "ms"                    },
-  { "[title].fade_mode",                       "fade"                  },
-  { "[title].fade_delay",                      "500"                   },
-  { "[title].post_delay",                      "250"                   },
-  { "[title].auto_delay",                      "-1"                    },
-  { "[title].auto_delay_unit",                 "ms"                    },
-
-  { "[titlescreen_initial].sort_priority",     "0"                     },
-  { "[titlescreen_initial].fade_mode",         ARG_DEFAULT             },
-  { "[titlescreen_initial].fade_delay",                ARG_DEFAULT             },
-  { "[titlescreen_initial].post_delay",                ARG_DEFAULT             },
-  { "[titlescreen_initial].auto_delay",                ARG_DEFAULT             },
-  { "[titlescreen_initial].auto_delay_unit",   ARG_DEFAULT             },
-  { "[titlescreen].sort_priority",             "0"                     },
-  { "[titlescreen].fade_mode",                 ARG_DEFAULT             },
-  { "[titlescreen].fade_delay",                        ARG_DEFAULT             },
-  { "[titlescreen].post_delay",                        ARG_DEFAULT             },
-  { "[titlescreen].auto_delay",                        ARG_DEFAULT             },
-  { "[titlescreen].auto_delay_unit",           ARG_DEFAULT             },
-
-  { "titlescreen_initial_1.sort_priority",     ARG_DEFAULT             },
-  { "titlescreen_initial_1.fade_mode",         ARG_DEFAULT             },
-  { "titlescreen_initial_1.fade_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_1.post_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_1.auto_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_1.auto_delay_unit",   ARG_DEFAULT             },
-  { "titlescreen_initial_2.sort_priority",     ARG_DEFAULT             },
-  { "titlescreen_initial_2.fade_mode",         ARG_DEFAULT             },
-  { "titlescreen_initial_2.fade_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_2.post_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_2.auto_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_2.auto_delay_unit",   ARG_DEFAULT             },
-  { "titlescreen_initial_3.sort_priority",     ARG_DEFAULT             },
-  { "titlescreen_initial_3.fade_mode",         ARG_DEFAULT             },
-  { "titlescreen_initial_3.fade_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_3.post_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_3.auto_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_3.auto_delay_unit",   ARG_DEFAULT             },
-  { "titlescreen_initial_4.sort_priority",     ARG_DEFAULT             },
-  { "titlescreen_initial_4.fade_mode",         ARG_DEFAULT             },
-  { "titlescreen_initial_4.fade_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_4.post_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_4.auto_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_4.auto_delay_unit",   ARG_DEFAULT             },
-  { "titlescreen_initial_5.sort_priority",     ARG_DEFAULT             },
-  { "titlescreen_initial_5.fade_mode",         ARG_DEFAULT             },
-  { "titlescreen_initial_5.fade_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_5.post_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_5.auto_delay",                ARG_DEFAULT             },
-  { "titlescreen_initial_5.auto_delay_unit",   ARG_DEFAULT             },
-  { "titlescreen_1.sort_priority",             ARG_DEFAULT             },
-  { "titlescreen_1.fade_mode",                 ARG_DEFAULT             },
-  { "titlescreen_1.fade_delay",                        ARG_DEFAULT             },
-  { "titlescreen_1.post_delay",                        ARG_DEFAULT             },
-  { "titlescreen_1.auto_delay",                        ARG_DEFAULT             },
-  { "titlescreen_1.auto_delay_unit",           ARG_DEFAULT             },
-  { "titlescreen_2.sort_priority",             ARG_DEFAULT             },
-  { "titlescreen_2.fade_mode",                 ARG_DEFAULT             },
-  { "titlescreen_2.fade_delay",                        ARG_DEFAULT             },
-  { "titlescreen_2.post_delay",                        ARG_DEFAULT             },
-  { "titlescreen_2.auto_delay",                        ARG_DEFAULT             },
-  { "titlescreen_2.auto_delay_unit",           ARG_DEFAULT             },
-  { "titlescreen_3.sort_priority",             ARG_DEFAULT             },
-  { "titlescreen_3.fade_mode",                 ARG_DEFAULT             },
-  { "titlescreen_3.fade_delay",                        ARG_DEFAULT             },
-  { "titlescreen_3.post_delay",                        ARG_DEFAULT             },
-  { "titlescreen_3.auto_delay",                        ARG_DEFAULT             },
-  { "titlescreen_3.auto_delay_unit",           ARG_DEFAULT             },
-  { "titlescreen_4.sort_priority",             ARG_DEFAULT             },
-  { "titlescreen_4.fade_mode",                 ARG_DEFAULT             },
-  { "titlescreen_4.fade_delay",                        ARG_DEFAULT             },
-  { "titlescreen_4.post_delay",                        ARG_DEFAULT             },
-  { "titlescreen_4.auto_delay",                        ARG_DEFAULT             },
-  { "titlescreen_4.auto_delay_unit",           ARG_DEFAULT             },
-  { "titlescreen_5.sort_priority",             ARG_DEFAULT             },
-  { "titlescreen_5.fade_mode",                 ARG_DEFAULT             },
-  { "titlescreen_5.fade_delay",                        ARG_DEFAULT             },
-  { "titlescreen_5.post_delay",                        ARG_DEFAULT             },
-  { "titlescreen_5.auto_delay",                        ARG_DEFAULT             },
-  { "titlescreen_5.auto_delay_unit",           ARG_DEFAULT             },
-
-  { "[titlemessage_initial].x",                        "-1"                    },
-  { "[titlemessage_initial].y",                        "-1"                    },
-  { "[titlemessage_initial].width",            "-1"                    },
-  { "[titlemessage_initial].height",           "-1"                    },
-  { "[titlemessage_initial].chars",            "-1"                    },
-  { "[titlemessage_initial].lines",            "-1"                    },
-  { "[titlemessage_initial].align",            "center"                },
-  { "[titlemessage_initial].valign",           "middle"                },
-  { "[titlemessage_initial].font",             "font.text_1"           },
-  { "[titlemessage_initial].autowrap",         "false"                 },
-  { "[titlemessage_initial].centered",         "false"                 },
-  { "[titlemessage_initial].parse_comments",   "false"                 },
-  { "[titlemessage_initial].sort_priority",    "0"                     },
-  { "[titlemessage_initial].fade_mode",                ARG_DEFAULT             },
-  { "[titlemessage_initial].fade_delay",       ARG_DEFAULT             },
-  { "[titlemessage_initial].post_delay",       ARG_DEFAULT             },
-  { "[titlemessage_initial].auto_delay",       ARG_DEFAULT             },
-  { "[titlemessage_initial].auto_delay_unit",  ARG_DEFAULT             },
-  { "[titlemessage].x",                                "-1"                    },
-  { "[titlemessage].y",                                "-1"                    },
-  { "[titlemessage].width",                    "-1"                    },
-  { "[titlemessage].height",                   "-1"                    },
-  { "[titlemessage].chars",                    "-1"                    },
-  { "[titlemessage].lines",                    "-1"                    },
-  { "[titlemessage].align",                    "center"                },
-  { "[titlemessage].valign",                   "middle"                },
-  { "[titlemessage].font",                     "font.text_1"           },
-  { "[titlemessage].autowrap",                 "false"                 },
-  { "[titlemessage].centered",                 "false"                 },
-  { "[titlemessage].parse_comments",           "false"                 },
-  { "[titlemessage].sort_priority",            "0"                     },
-  { "[titlemessage].fade_mode",                        ARG_DEFAULT             },
-  { "[titlemessage].fade_delay",               ARG_DEFAULT             },
-  { "[titlemessage].post_delay",               ARG_DEFAULT             },
-  { "[titlemessage].auto_delay",               ARG_DEFAULT             },
-  { "[titlemessage].auto_delay_unit",          ARG_DEFAULT             },
-
-  { "titlemessage_initial_1.x",                        ARG_DEFAULT             },
-  { "titlemessage_initial_1.y",                        ARG_DEFAULT             },
-  { "titlemessage_initial_1.width",            ARG_DEFAULT             },
-  { "titlemessage_initial_1.height",           ARG_DEFAULT             },
-  { "titlemessage_initial_1.chars",            ARG_DEFAULT             },
-  { "titlemessage_initial_1.lines",            ARG_DEFAULT             },
-  { "titlemessage_initial_1.align",            ARG_DEFAULT             },
-  { "titlemessage_initial_1.valign",           ARG_DEFAULT             },
-  { "titlemessage_initial_1.font",             ARG_DEFAULT             },
-  { "titlemessage_initial_1.autowrap",         ARG_DEFAULT             },
-  { "titlemessage_initial_1.centered",         ARG_DEFAULT             },
-  { "titlemessage_initial_1.parse_comments",   ARG_DEFAULT             },
-  { "titlemessage_initial_1.sort_priority",    ARG_DEFAULT             },
-  { "titlemessage_initial_1.fade_mode",                ARG_DEFAULT             },
-  { "titlemessage_initial_1.fade_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_1.post_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_1.auto_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_1.auto_delay_unit",  ARG_DEFAULT             },
-  { "titlemessage_initial_2.x",                        ARG_DEFAULT             },
-  { "titlemessage_initial_2.y",                        ARG_DEFAULT             },
-  { "titlemessage_initial_2.width",            ARG_DEFAULT             },
-  { "titlemessage_initial_2.height",           ARG_DEFAULT             },
-  { "titlemessage_initial_2.chars",            ARG_DEFAULT             },
-  { "titlemessage_initial_2.lines",            ARG_DEFAULT             },
-  { "titlemessage_initial_2.align",            ARG_DEFAULT             },
-  { "titlemessage_initial_2.valign",           ARG_DEFAULT             },
-  { "titlemessage_initial_2.font",             ARG_DEFAULT             },
-  { "titlemessage_initial_2.autowrap",         ARG_DEFAULT             },
-  { "titlemessage_initial_2.centered",         ARG_DEFAULT             },
-  { "titlemessage_initial_2.parse_comments",   ARG_DEFAULT             },
-  { "titlemessage_initial_2.sort_priority",    ARG_DEFAULT             },
-  { "titlemessage_initial_2.fade_mode",                ARG_DEFAULT             },
-  { "titlemessage_initial_2.fade_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_2.post_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_2.auto_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_2.auto_delay_unit",  ARG_DEFAULT             },
-  { "titlemessage_initial_3.x",                        ARG_DEFAULT             },
-  { "titlemessage_initial_3.y",                        ARG_DEFAULT             },
-  { "titlemessage_initial_3.width",            ARG_DEFAULT             },
-  { "titlemessage_initial_3.height",           ARG_DEFAULT             },
-  { "titlemessage_initial_3.chars",            ARG_DEFAULT             },
-  { "titlemessage_initial_3.lines",            ARG_DEFAULT             },
-  { "titlemessage_initial_3.align",            ARG_DEFAULT             },
-  { "titlemessage_initial_3.valign",           ARG_DEFAULT             },
-  { "titlemessage_initial_3.font",             ARG_DEFAULT             },
-  { "titlemessage_initial_3.autowrap",         ARG_DEFAULT             },
-  { "titlemessage_initial_3.centered",         ARG_DEFAULT             },
-  { "titlemessage_initial_3.parse_comments",   ARG_DEFAULT             },
-  { "titlemessage_initial_3.sort_priority",    ARG_DEFAULT             },
-  { "titlemessage_initial_3.fade_mode",                ARG_DEFAULT             },
-  { "titlemessage_initial_3.fade_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_3.post_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_3.auto_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_3.auto_delay_unit",  ARG_DEFAULT             },
-  { "titlemessage_initial_4.x",                        ARG_DEFAULT             },
-  { "titlemessage_initial_4.y",                        ARG_DEFAULT             },
-  { "titlemessage_initial_4.width",            ARG_DEFAULT             },
-  { "titlemessage_initial_4.height",           ARG_DEFAULT             },
-  { "titlemessage_initial_4.chars",            ARG_DEFAULT             },
-  { "titlemessage_initial_4.lines",            ARG_DEFAULT             },
-  { "titlemessage_initial_4.align",            ARG_DEFAULT             },
-  { "titlemessage_initial_4.valign",           ARG_DEFAULT             },
-  { "titlemessage_initial_4.font",             ARG_DEFAULT             },
-  { "titlemessage_initial_4.autowrap",         ARG_DEFAULT             },
-  { "titlemessage_initial_4.centered",         ARG_DEFAULT             },
-  { "titlemessage_initial_4.parse_comments",   ARG_DEFAULT             },
-  { "titlemessage_initial_4.sort_priority",    ARG_DEFAULT             },
-  { "titlemessage_initial_4.fade_mode",                ARG_DEFAULT             },
-  { "titlemessage_initial_4.fade_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_4.post_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_4.auto_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_4.auto_delay_unit",  ARG_DEFAULT             },
-  { "titlemessage_initial_5.x",                        ARG_DEFAULT             },
-  { "titlemessage_initial_5.y",                        ARG_DEFAULT             },
-  { "titlemessage_initial_5.width",            ARG_DEFAULT             },
-  { "titlemessage_initial_5.height",           ARG_DEFAULT             },
-  { "titlemessage_initial_5.chars",            ARG_DEFAULT             },
-  { "titlemessage_initial_5.lines",            ARG_DEFAULT             },
-  { "titlemessage_initial_5.align",            ARG_DEFAULT             },
-  { "titlemessage_initial_5.valign",           ARG_DEFAULT             },
-  { "titlemessage_initial_5.font",             ARG_DEFAULT             },
-  { "titlemessage_initial_5.autowrap",         ARG_DEFAULT             },
-  { "titlemessage_initial_5.centered",         ARG_DEFAULT             },
-  { "titlemessage_initial_5.parse_comments",   ARG_DEFAULT             },
-  { "titlemessage_initial_5.sort_priority",    ARG_DEFAULT             },
-  { "titlemessage_initial_5.fade_mode",                ARG_DEFAULT             },
-  { "titlemessage_initial_5.fade_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_5.post_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_5.auto_delay",       ARG_DEFAULT             },
-  { "titlemessage_initial_5.auto_delay_unit",  ARG_DEFAULT             },
-  { "titlemessage_1.x",                                ARG_DEFAULT             },
-  { "titlemessage_1.y",                                ARG_DEFAULT             },
-  { "titlemessage_1.width",                    ARG_DEFAULT             },
-  { "titlemessage_1.height",                   ARG_DEFAULT             },
-  { "titlemessage_1.chars",                    ARG_DEFAULT             },
-  { "titlemessage_1.lines",                    ARG_DEFAULT             },
-  { "titlemessage_1.align",                    ARG_DEFAULT             },
-  { "titlemessage_1.valign",                   ARG_DEFAULT             },
-  { "titlemessage_1.font",                     ARG_DEFAULT             },
-  { "titlemessage_1.autowrap",                 ARG_DEFAULT             },
-  { "titlemessage_1.centered",                 ARG_DEFAULT             },
-  { "titlemessage_1.parse_comments",           ARG_DEFAULT             },
-  { "titlemessage_1.sort_priority",            ARG_DEFAULT             },
-  { "titlemessage_1.fade_mode",                        ARG_DEFAULT             },
-  { "titlemessage_1.fade_delay",               ARG_DEFAULT             },
-  { "titlemessage_1.post_delay",               ARG_DEFAULT             },
-  { "titlemessage_1.auto_delay",               ARG_DEFAULT             },
-  { "titlemessage_1.auto_delay_unit",          ARG_DEFAULT             },
-  { "titlemessage_2.x",                                ARG_DEFAULT             },
-  { "titlemessage_2.y",                                ARG_DEFAULT             },
-  { "titlemessage_2.width",                    ARG_DEFAULT             },
-  { "titlemessage_2.height",                   ARG_DEFAULT             },
-  { "titlemessage_2.chars",                    ARG_DEFAULT             },
-  { "titlemessage_2.lines",                    ARG_DEFAULT             },
-  { "titlemessage_2.align",                    ARG_DEFAULT             },
-  { "titlemessage_2.valign",                   ARG_DEFAULT             },
-  { "titlemessage_2.font",                     ARG_DEFAULT             },
-  { "titlemessage_2.autowrap",                 ARG_DEFAULT             },
-  { "titlemessage_2.centered",                 ARG_DEFAULT             },
-  { "titlemessage_2.parse_comments",           ARG_DEFAULT             },
-  { "titlemessage_2.sort_priority",            ARG_DEFAULT             },
-  { "titlemessage_2.fade_mode",                        ARG_DEFAULT             },
-  { "titlemessage_2.fade_delay",               ARG_DEFAULT             },
-  { "titlemessage_2.post_delay",               ARG_DEFAULT             },
-  { "titlemessage_2.auto_delay",               ARG_DEFAULT             },
-  { "titlemessage_2.auto_delay_unit",          ARG_DEFAULT             },
-  { "titlemessage_3.x",                                ARG_DEFAULT             },
-  { "titlemessage_3.y",                                ARG_DEFAULT             },
-  { "titlemessage_3.width",                    ARG_DEFAULT             },
-  { "titlemessage_3.height",                   ARG_DEFAULT             },
-  { "titlemessage_3.chars",                    ARG_DEFAULT             },
-  { "titlemessage_3.lines",                    ARG_DEFAULT             },
-  { "titlemessage_3.align",                    ARG_DEFAULT             },
-  { "titlemessage_3.valign",                   ARG_DEFAULT             },
-  { "titlemessage_3.font",                     ARG_DEFAULT             },
-  { "titlemessage_3.autowrap",                 ARG_DEFAULT             },
-  { "titlemessage_3.centered",                 ARG_DEFAULT             },
-  { "titlemessage_3.parse_comments",           ARG_DEFAULT             },
-  { "titlemessage_3.sort_priority",            ARG_DEFAULT             },
-  { "titlemessage_3.fade_mode",                        ARG_DEFAULT             },
-  { "titlemessage_3.fade_delay",               ARG_DEFAULT             },
-  { "titlemessage_3.post_delay",               ARG_DEFAULT             },
-  { "titlemessage_3.auto_delay",               ARG_DEFAULT             },
-  { "titlemessage_3.auto_delay_unit",          ARG_DEFAULT             },
-  { "titlemessage_4.x",                                ARG_DEFAULT             },
-  { "titlemessage_4.y",                                ARG_DEFAULT             },
-  { "titlemessage_4.width",                    ARG_DEFAULT             },
-  { "titlemessage_4.height",                   ARG_DEFAULT             },
-  { "titlemessage_4.chars",                    ARG_DEFAULT             },
-  { "titlemessage_4.lines",                    ARG_DEFAULT             },
-  { "titlemessage_4.align",                    ARG_DEFAULT             },
-  { "titlemessage_4.valign",                   ARG_DEFAULT             },
-  { "titlemessage_4.font",                     ARG_DEFAULT             },
-  { "titlemessage_4.autowrap",                 ARG_DEFAULT             },
-  { "titlemessage_4.centered",                 ARG_DEFAULT             },
-  { "titlemessage_4.parse_comments",           ARG_DEFAULT             },
-  { "titlemessage_4.sort_priority",            ARG_DEFAULT             },
-  { "titlemessage_4.fade_mode",                        ARG_DEFAULT             },
-  { "titlemessage_4.fade_delay",               ARG_DEFAULT             },
-  { "titlemessage_4.post_delay",               ARG_DEFAULT             },
-  { "titlemessage_4.auto_delay",               ARG_DEFAULT             },
-  { "titlemessage_4.auto_delay_unit",          ARG_DEFAULT             },
-  { "titlemessage_5.x",                                ARG_DEFAULT             },
-  { "titlemessage_5.y",                                ARG_DEFAULT             },
-  { "titlemessage_5.width",                    ARG_DEFAULT             },
-  { "titlemessage_5.height",                   ARG_DEFAULT             },
-  { "titlemessage_5.chars",                    ARG_DEFAULT             },
-  { "titlemessage_5.lines",                    ARG_DEFAULT             },
-  { "titlemessage_5.align",                    ARG_DEFAULT             },
-  { "titlemessage_5.valign",                   ARG_DEFAULT             },
-  { "titlemessage_5.font",                     ARG_DEFAULT             },
-  { "titlemessage_5.autowrap",                 ARG_DEFAULT             },
-  { "titlemessage_5.centered",                 ARG_DEFAULT             },
-  { "titlemessage_5.parse_comments",           ARG_DEFAULT             },
-  { "titlemessage_5.sort_priority",            ARG_DEFAULT             },
-  { "titlemessage_5.fade_mode",                        ARG_DEFAULT             },
-  { "titlemessage_5.fade_delay",               ARG_DEFAULT             },
-  { "titlemessage_5.post_delay",               ARG_DEFAULT             },
-  { "titlemessage_5.auto_delay",               ARG_DEFAULT             },
-  { "titlemessage_5.auto_delay_unit",          ARG_DEFAULT             },
-
-  { "readme.x",                                        "-1"                    },
-  { "readme.y",                                        "-1"                    },
-  { "readme.width",                            "-1"                    },
-  { "readme.height",                           "-1"                    },
-  { "readme.chars",                            "-1"                    },
-  { "readme.lines",                            "-1"                    },
-  { "readme.align",                            "center"                },
-  { "readme.valign",                           "top"                   },
-  { "readme.font",                             "font.info.levelset"    },
-  { "readme.autowrap",                         "true"                  },
-  { "readme.centered",                         "false"                 },
-  { "readme.parse_comments",                   "true"                  },
-  { "readme.sort_priority",                    "0"                     },
-
-  { "global.num_toons",                                "20"                    },
-
-  { "border.draw_masked.TITLE",                        "false"                 },
-  { "border.draw_masked.MAIN",                 "false"                 },
-  { "border.draw_masked.NAMES",                        "false"                 },
-  { "border.draw_masked.LEVELS",               "false"                 },
-  { "border.draw_masked.LEVELNR",              "false"                 },
-  { "border.draw_masked.SCORES",               "false"                 },
-  { "border.draw_masked.EDITOR",               "false"                 },
-  { "border.draw_masked.INFO",                 "false"                 },
-  { "border.draw_masked.SETUP",                        "false"                 },
-  { "border.draw_masked.PLAYING",              "false"                 },
-  { "border.draw_masked.DOOR",                 "false"                 },
-
-  { "border.draw_masked_when_fading",          "true"                  },
-
-  { "init.busy.x",                             "-1"                    },
-  { "init.busy.y",                             "-1"                    },
-  { "init.busy.align",                         "center"                },
-  { "init.busy.valign",                                "middle"                },
-
-  { "menu.enter_menu.fade_mode",               "none"                  },
-  { "menu.enter_menu.fade_delay",              "250"                   },
-  { "menu.enter_menu.post_delay",              "125"                   },
-  { "menu.leave_menu.fade_mode",               "none"                  },
-  { "menu.leave_menu.fade_delay",              "250"                   },
-  { "menu.leave_menu.post_delay",              "125"                   },
-  { "menu.enter_screen.fade_mode",             "fade"                  },
-  { "menu.enter_screen.fade_delay",            "250"                   },
-  { "menu.enter_screen.post_delay",            "125"                   },
-  { "menu.leave_screen.fade_mode",             "fade"                  },
-  { "menu.leave_screen.fade_delay",            "250"                   },
-  { "menu.leave_screen.post_delay",            "125"                   },
-  { "menu.next_screen.fade_mode",              "crossfade"             },
-  { "menu.next_screen.fade_delay",             "250"                   },
-  { "menu.next_screen.post_delay",             "125"                   },
-  { "menu.enter_screen.TITLE.fade_mode",       "fade"                  },
-  { "menu.enter_screen.TITLE.fade_delay",      "500"                   },
-  { "menu.enter_screen.TITLE.post_delay",      "250"                   },
-  { "menu.enter_screen.TITLE.auto_delay",      "-1"                    },
-  { "menu.enter_screen.TITLE.auto_delay_unit", "-1"                    },
-  { "menu.enter_screen.SCORES.fade_mode",      ARG_DEFAULT             },
-  { "menu.enter_screen.SCORES.fade_delay",     ARG_DEFAULT             },
-  { "menu.enter_screen.SCORES.post_delay",     ARG_DEFAULT             },
-  { "menu.enter_screen.EDITOR.fade_mode",      ARG_DEFAULT             },
-  { "menu.enter_screen.EDITOR.fade_delay",     ARG_DEFAULT             },
-  { "menu.enter_screen.EDITOR.post_delay",     ARG_DEFAULT             },
-  { "menu.enter_screen.INFO.fade_mode",                ARG_DEFAULT             },
-  { "menu.enter_screen.INFO.fade_delay",       ARG_DEFAULT             },
-  { "menu.enter_screen.INFO.post_delay",       ARG_DEFAULT             },
-  { "menu.enter_screen.PLAYING.fade_mode",     ARG_DEFAULT             },
-  { "menu.enter_screen.PLAYING.fade_delay",    ARG_DEFAULT             },
-  { "menu.enter_screen.PLAYING.post_delay",    ARG_DEFAULT             },
-  { "menu.leave_screen.TITLE.fade_mode",       "fade"                  },
-  { "menu.leave_screen.TITLE.fade_delay",      "500"                   },
-  { "menu.leave_screen.TITLE.post_delay",      "250"                   },
-  { "menu.leave_screen.TITLE.auto_delay",      "-1"                    },
-  { "menu.leave_screen.TITLE.auto_delay_unit", "-1"                    },
-  { "menu.leave_screen.SCORES.fade_mode",      ARG_DEFAULT             },
-  { "menu.leave_screen.SCORES.fade_delay",     ARG_DEFAULT             },
-  { "menu.leave_screen.SCORES.post_delay",     ARG_DEFAULT             },
-  { "menu.leave_screen.EDITOR.fade_mode",      ARG_DEFAULT             },
-  { "menu.leave_screen.EDITOR.fade_delay",     ARG_DEFAULT             },
-  { "menu.leave_screen.EDITOR.post_delay",     ARG_DEFAULT             },
-  { "menu.leave_screen.INFO.fade_mode",                ARG_DEFAULT             },
-  { "menu.leave_screen.INFO.fade_delay",       ARG_DEFAULT             },
-  { "menu.leave_screen.INFO.post_delay",       ARG_DEFAULT             },
-  { "menu.leave_screen.PLAYING.fade_mode",     ARG_DEFAULT             },
-  { "menu.leave_screen.PLAYING.fade_delay",    ARG_DEFAULT             },
-  { "menu.leave_screen.PLAYING.post_delay",    ARG_DEFAULT             },
-  { "menu.next_screen.TITLE.fade_mode",                "fade"                  },
-  { "menu.next_screen.TITLE.fade_delay",       "500"                   },
-  { "menu.next_screen.TITLE.post_delay",       "250"                   },
-  { "menu.next_screen.TITLE.auto_delay",       "-1"                    },
-  { "menu.next_screen.TITLE.auto_delay_unit",  "-1"                    },
-  { "menu.next_screen.INFO.fade_mode",         ARG_DEFAULT             },
-  { "menu.next_screen.INFO.fade_delay",                ARG_DEFAULT             },
-  { "menu.next_screen.INFO.post_delay",                ARG_DEFAULT             },
-
-  { "menu.draw_xoffset",                       "0"                     },
-  { "menu.draw_yoffset",                       "0"                     },
-  { "menu.draw_xoffset.MAIN",                  "0"                     },
-  { "menu.draw_yoffset.MAIN",                  "0"                     },
-  { "menu.draw_xoffset.NAMES",                 "0"                     },
-  { "menu.draw_yoffset.NAMES",                 "0"                     },
-  { "menu.draw_xoffset.LEVELS",                        "0"                     },
-  { "menu.draw_yoffset.LEVELS",                        "0"                     },
-  { "menu.draw_xoffset.LEVELNR",               "0"                     },
-  { "menu.draw_yoffset.LEVELNR",               "0"                     },
-  { "menu.draw_xoffset.SCORES",                        "0"                     },
-  { "menu.draw_yoffset.SCORES",                        "0"                     },
-  { "menu.draw_xoffset.EDITOR",                        "0"                     },
-  { "menu.draw_yoffset.EDITOR",                        "0"                     },
-  { "menu.draw_xoffset.INFO",                  "0"                     },
-  { "menu.draw_yoffset.INFO",                  "0"                     },
-  { "menu.draw_xoffset.INFO[TITLE]",           "0"                     },
-  { "menu.draw_yoffset.INFO[TITLE]",           "0"                     },
-  { "menu.draw_xoffset.INFO[ELEMENTS]",                "0"                     },
-  { "menu.draw_yoffset.INFO[ELEMENTS]",                "0"                     },
-  { "menu.draw_xoffset.INFO[MUSIC]",           "0"                     },
-  { "menu.draw_yoffset.INFO[MUSIC]",           "0"                     },
-  { "menu.draw_xoffset.INFO[CREDITS]",         "0"                     },
-  { "menu.draw_yoffset.INFO[CREDITS]",         "0"                     },
-  { "menu.draw_xoffset.INFO[PROGRAM]",         "0"                     },
-  { "menu.draw_yoffset.INFO[PROGRAM]",         "0"                     },
-  { "menu.draw_xoffset.INFO[VERSION]",         "0"                     },
-  { "menu.draw_yoffset.INFO[VERSION]",         "0"                     },
-  { "menu.draw_xoffset.INFO[LEVELSET]",                "0"                     },
-  { "menu.draw_yoffset.INFO[LEVELSET]",                "0"                     },
-  { "menu.draw_xoffset.SETUP",                 "0"                     },
-  { "menu.draw_yoffset.SETUP",                 "0"                     },
-  { "menu.draw_xoffset.SETUP[GAME]",           "0"                     },
-  { "menu.draw_yoffset.SETUP[GAME]",           "0"                     },
-  { "menu.draw_xoffset.SETUP[ENGINES]",                "0"                     },
-  { "menu.draw_yoffset.SETUP[ENGINES]",                "0"                     },
-  { "menu.draw_xoffset.SETUP[EDITOR]",         "0"                     },
-  { "menu.draw_yoffset.SETUP[EDITOR]",         "0"                     },
-  { "menu.draw_xoffset.SETUP[GRAPHICS]",       "0"                     },
-  { "menu.draw_yoffset.SETUP[GRAPHICS]",       "0"                     },
-  { "menu.draw_xoffset.SETUP[SOUND]",          "0"                     },
-  { "menu.draw_yoffset.SETUP[SOUND]",          "0"                     },
-  { "menu.draw_xoffset.SETUP[ARTWORK]",                "0"                     },
-  { "menu.draw_yoffset.SETUP[ARTWORK]",                "0"                     },
-  { "menu.draw_xoffset.SETUP[INPUT]",          "0"                     },
-  { "menu.draw_yoffset.SETUP[INPUT]",          "0"                     },
-  { "menu.draw_xoffset.SETUP[TOUCH]",          "0"                     },
-  { "menu.draw_yoffset.SETUP[TOUCH]",          "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS]",      "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS]",      "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS_1]",    "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS_1]",    "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS_2]",    "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS_2]",    "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS_3]",    "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS_3]",    "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS_4]",    "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS_4]",    "0"                     },
-  { "menu.draw_xoffset.SETUP[SHORTCUTS_5]",    "0"                     },
-  { "menu.draw_yoffset.SETUP[SHORTCUTS_5]",    "0"                     },
-  { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]", "0"                     },
-  { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]", "0"                     },
-  { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]",   "0"                     },
-  { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]",   "0"                     },
-
-  { "menu.scrollbar_xoffset",                  "0"                     },
-
-  { "menu.list.SETUP[CHOOSE_OTHER].align",     "left"                  },
-  { "menu.list.SETUP[CHOOSE_OTHER].valign",    "top"                   },
-
-  { "menu.list_size",                          "-1"                    },
-  { "menu.list_size.NAMES",                    "-1"                    },
-  { "menu.list_size.LEVELS",                   "-1"                    },
-  { "menu.list_size.LEVELNR",                  "-1"                    },
-  { "menu.list_size.SCORES",                   "-1"                    },
-  { "menu.list_size.INFO",                     "-1"                    },
-  { "menu.list_size.INFO[ELEMENTS]",           "-1"                    },
-  { "menu.list_size.SETUP",                    "-1"                    },
-
-  { "menu.left_spacing.INFO",                  "16"                    },
-  { "menu.left_spacing.INFO[TITLE]",           "16"                    },
-  { "menu.left_spacing.INFO[ELEMENTS]",                "16"                    },
-  { "menu.left_spacing.INFO[MUSIC]",           "16"                    },
-  { "menu.left_spacing.INFO[CREDITS]",         "16"                    },
-  { "menu.left_spacing.INFO[PROGRAM]",         "16"                    },
-  { "menu.left_spacing.INFO[VERSION]",         "16"                    },
-  { "menu.left_spacing.INFO[LEVELSET]",                "16"                    },
-  { "menu.left_spacing.SETUP[INPUT]",          "16"                    },
-
-  { "menu.right_spacing.INFO",                 "16"                    },
-  { "menu.right_spacing.INFO[TITLE]",          "16"                    },
-  { "menu.right_spacing.INFO[ELEMENTS]",       "16"                    },
-  { "menu.right_spacing.INFO[MUSIC]",          "16"                    },
-  { "menu.right_spacing.INFO[CREDITS]",                "16"                    },
-  { "menu.right_spacing.INFO[PROGRAM]",                "16"                    },
-  { "menu.right_spacing.INFO[VERSION]",                "16"                    },
-  { "menu.right_spacing.INFO[LEVELSET]",       "16"                    },
-  { "menu.right_spacing.SETUP[INPUT]",         "16"                    },
-
-  { "menu.top_spacing.INFO",                   "100"                   },
-  { "menu.top_spacing.INFO[TITLE]",            "100"                   },
-  { "menu.top_spacing.INFO[ELEMENTS]",         "100"                   },
-  { "menu.top_spacing.INFO[MUSIC]",            "100"                   },
-  { "menu.top_spacing.INFO[CREDITS]",          "100"                   },
-  { "menu.top_spacing.INFO[PROGRAM]",          "100"                   },
-  { "menu.top_spacing.INFO[VERSION]",          "100"                   },
-  { "menu.top_spacing.INFO[LEVELSET]",         "100"                   },
-  { "menu.top_spacing.SETUP[INPUT]",           "100"                   },
-
-  { "menu.bottom_spacing.INFO",                        "20"                    },
-  { "menu.bottom_spacing.INFO[TITLE]",         "20"                    },
-  { "menu.bottom_spacing.INFO[ELEMENTS]",      "20"                    },
-  { "menu.bottom_spacing.INFO[MUSIC]",         "20"                    },
-  { "menu.bottom_spacing.INFO[CREDITS]",       "20"                    },
-  { "menu.bottom_spacing.INFO[PROGRAM]",       "20"                    },
-  { "menu.bottom_spacing.INFO[VERSION]",       "20"                    },
-  { "menu.bottom_spacing.INFO[LEVELSET]",      "20"                    },
-  { "menu.bottom_spacing.SETUP[INPUT]",                "20"                    },
-
-  { "menu.paragraph_spacing.INFO",             "-3"                    },
-  { "menu.paragraph_spacing.INFO[TITLE]",      "-3"                    },
-  { "menu.paragraph_spacing.INFO[ELEMENTS]",   "-3"                    },
-  { "menu.paragraph_spacing.INFO[MUSIC]",      "-3"                    },
-  { "menu.paragraph_spacing.INFO[CREDITS]",    "-3"                    },
-  { "menu.paragraph_spacing.INFO[PROGRAM]",    "-3"                    },
-  { "menu.paragraph_spacing.INFO[VERSION]",    "-2"                    },
-  { "menu.paragraph_spacing.INFO[LEVELSET]",   "-3"                    },
-  { "menu.paragraph_spacing.SETUP[INPUT]",     "-1"                    },
-
-  { "menu.headline1_spacing.INFO",             "-2"                    },
-  { "menu.headline1_spacing.INFO[TITLE]",      "-2"                    },
-  { "menu.headline1_spacing.INFO[ELEMENTS]",   "-2"                    },
-  { "menu.headline1_spacing.INFO[MUSIC]",      "-2"                    },
-  { "menu.headline1_spacing.INFO[CREDITS]",    "-2"                    },
-  { "menu.headline1_spacing.INFO[PROGRAM]",    "-2"                    },
-  { "menu.headline1_spacing.INFO[VERSION]",    "-2"                    },
-  { "menu.headline1_spacing.INFO[LEVELSET]",   "-2"                    },
-  { "menu.headline1_spacing.SETUP[INPUT]",     "-2"                    },
-
-  { "menu.headline2_spacing.INFO",             "-1"                    },
-  { "menu.headline2_spacing.INFO[TITLE]",      "-1"                    },
-  { "menu.headline2_spacing.INFO[ELEMENTS]",   "-1"                    },
-  { "menu.headline2_spacing.INFO[MUSIC]",      "-1"                    },
-  { "menu.headline2_spacing.INFO[CREDITS]",    "-1"                    },
-  { "menu.headline2_spacing.INFO[PROGRAM]",    "-1"                    },
-  { "menu.headline2_spacing.INFO[VERSION]",    "-1"                    },
-  { "menu.headline2_spacing.INFO[LEVELSET]",   "-1"                    },
-  { "menu.headline2_spacing.SETUP[INPUT]",     "-1"                    },
-
-  { "menu.line_spacing.INFO",                  "0"                     },
-  { "menu.line_spacing.INFO[TITLE]",           "0"                     },
-  { "menu.line_spacing.INFO[ELEMENTS]",                "0"                     },
-  { "menu.line_spacing.INFO[MUSIC]",           "0"                     },
-  { "menu.line_spacing.INFO[CREDITS]",         "0"                     },
-  { "menu.line_spacing.INFO[PROGRAM]",         "0"                     },
-  { "menu.line_spacing.INFO[VERSION]",         "0"                     },
-  { "menu.line_spacing.INFO[LEVELSET]",                "0"                     },
-  { "menu.line_spacing.SETUP[INPUT]",          "0"                     },
-
-  { "menu.extra_spacing.INFO",                 "2"                     },
-  { "menu.extra_spacing.INFO[TITLE]",          "2"                     },
-  { "menu.extra_spacing.INFO[ELEMENTS]",       "2"                     },
-  { "menu.extra_spacing.INFO[MUSIC]",          "2"                     },
-  { "menu.extra_spacing.INFO[CREDITS]",                "2"                     },
-  { "menu.extra_spacing.INFO[PROGRAM]",                "2"                     },
-  { "menu.extra_spacing.INFO[VERSION]",                "2"                     },
-  { "menu.extra_spacing.INFO[LEVELSET]",       "2"                     },
-  { "menu.extra_spacing.SETUP[INPUT]",         "2"                     },
-
-  { "main.button.name.x",                      "0"                     },
-  { "main.button.name.y",                      "64"                    },
-  { "main.button.levels.x",                    "0"                     },
-  { "main.button.levels.y",                    "96"                    },
-  { "main.button.scores.x",                    "0"                     },
-  { "main.button.scores.y",                    "128"                   },
-  { "main.button.editor.x",                    "0"                     },
-  { "main.button.editor.y",                    "160"                   },
-  { "main.button.info.x",                      "0"                     },
-  { "main.button.info.y",                      "192"                   },
-  { "main.button.game.x",                      "0"                     },
-  { "main.button.game.y",                      "224"                   },
-  { "main.button.setup.x",                     "0"                     },
-  { "main.button.setup.y",                     "256"                   },
-  { "main.button.quit.x",                      "0"                     },
-  { "main.button.quit.y",                      "288"                   },
-
-  { "main.button.first_level.x",               "-1"                    },
-  { "main.button.first_level.y",               "-1"                    },
-  { "main.button.last_level.x",                        "-1"                    },
-  { "main.button.last_level.y",                        "-1"                    },
-  { "main.button.level_number.x",              "-1"                    },
-  { "main.button.level_number.y",              "-1"                    },
-
-  { "main.button.prev_level.x",                        "320"                   },
-  { "main.button.prev_level.y",                        "96"                    },
-  { "main.button.next_level.x",                        "448"                   },
-  { "main.button.next_level.y",                        "96"                    },
-
-  { "main.button.insert_solution.x",           "-1"                    },
-  { "main.button.insert_solution.y",           "-1"                    },
-  { "main.button.play_solution.x",             "-1"                    },
-  { "main.button.play_solution.y",             "-1"                    },
-
-  { "main.button.switch_ecs_aga.x",            "-1"                    },
-  { "main.button.switch_ecs_aga.y",            "-1"                    },
-
-  { "main.text.name.x",                                "-1"                    },
-  { "main.text.name.y",                                "-1"                    },
-  { "main.text.name.width",                    "-1"                    },
-  { "main.text.name.height",                   "-1"                    },
-  { "main.text.name.align",                    "left"                  },
-  { "main.text.name.valign",                   "top"                   },
-  { "main.text.name.font",                     "font.menu_1"           },
-  { "main.text.levels.x",                      "-1"                    },
-  { "main.text.levels.y",                      "-1"                    },
-  { "main.text.levels.width",                  "-1"                    },
-  { "main.text.levels.height",                 "-1"                    },
-  { "main.text.levels.align",                  "left"                  },
-  { "main.text.levels.valign",                 "top"                   },
-  { "main.text.levels.font",                   "font.menu_1"           },
-  { "main.text.scores.x",                      "-1"                    },
-  { "main.text.scores.y",                      "-1"                    },
-  { "main.text.scores.width",                  "-1"                    },
-  { "main.text.scores.height",                 "-1"                    },
-  { "main.text.scores.align",                  "left"                  },
-  { "main.text.scores.valign",                 "top"                   },
-  { "main.text.scores.font",                   "font.menu_1"           },
-  { "main.text.editor.x",                      "-1"                    },
-  { "main.text.editor.y",                      "-1"                    },
-  { "main.text.editor.width",                  "-1"                    },
-  { "main.text.editor.height",                 "-1"                    },
-  { "main.text.editor.align",                  "left"                  },
-  { "main.text.editor.valign",                 "top"                   },
-  { "main.text.editor.font",                   "font.menu_1"           },
-  { "main.text.info.x",                                "-1"                    },
-  { "main.text.info.y",                                "-1"                    },
-  { "main.text.info.width",                    "-1"                    },
-  { "main.text.info.height",                   "-1"                    },
-  { "main.text.info.align",                    "left"                  },
-  { "main.text.info.valign",                   "top"                   },
-  { "main.text.info.font",                     "font.menu_1"           },
-  { "main.text.game.x",                                "-1"                    },
-  { "main.text.game.y",                                "-1"                    },
-  { "main.text.game.width",                    "-1"                    },
-  { "main.text.game.height",                   "-1"                    },
-  { "main.text.game.align",                    "left"                  },
-  { "main.text.game.valign",                   "top"                   },
-  { "main.text.game.font",                     "font.menu_1"           },
-  { "main.text.setup.x",                       "-1"                    },
-  { "main.text.setup.y",                       "-1"                    },
-  { "main.text.setup.width",                   "-1"                    },
-  { "main.text.setup.height",                  "-1"                    },
-  { "main.text.setup.align",                   "left"                  },
-  { "main.text.setup.valign",                  "top"                   },
-  { "main.text.setup.font",                    "font.menu_1"           },
-  { "main.text.quit.x",                                "-1"                    },
-  { "main.text.quit.y",                                "-1"                    },
-  { "main.text.quit.width",                    "-1"                    },
-  { "main.text.quit.height",                   "-1"                    },
-  { "main.text.quit.align",                    "left"                  },
-  { "main.text.quit.valign",                   "top"                   },
-  { "main.text.quit.font",                     "font.menu_1"           },
-
-  { "main.text.first_level.x",                 "488"                   },
-  { "main.text.first_level.y",                 "98"                    },
-  { "main.text.first_level.align",             "left"                  },
-  { "main.text.first_level.valign",            "top"                   },
-  { "main.text.first_level.digits",            "3"                     },
-  { "main.text.first_level.font",              "font.text_3"           },
-  { "main.text.last_level.x",                  "488"                   },
-  { "main.text.last_level.y",                  "112"                   },
-  { "main.text.last_level.align",              "left"                  },
-  { "main.text.last_level.valign",             "top"                   },
-  { "main.text.last_level.digits",             "3"                     },
-  { "main.text.last_level.font",               "font.text_3"           },
-  { "main.text.level_number.x",                        "352"                   },
-  { "main.text.level_number.y",                        "96"                    },
-  { "main.text.level_number.align",            "left"                  },
-  { "main.text.level_number.valign",           "top"                   },
-  { "main.text.level_number.digits",           "3"                     },
-  { "main.text.level_number.font",             "font.value_1"          },
-  { "main.text.level_info_1.x",                        "272"                   },
-  { "main.text.level_info_1.y",                        "352"                   },
-  { "main.text.level_info_1.align",            "center"                },
-  { "main.text.level_info_1.valign",           "top"                   },
-  { "main.text.level_info_1.chars",            "-1"                    },
-  { "main.text.level_info_1.font",             "font.text_1"           },
-  { "main.text.level_info_2.x",                        "272"                   },
-  { "main.text.level_info_2.y",                        "523"                   },
-  { "main.text.level_info_2.align",            "center"                },
-  { "main.text.level_info_2.valign",           "top"                   },
-  { "main.text.level_info_2.chars",            "-1"                    },
-  { "main.text.level_info_2.font",             "font.text_2"           },
-  { "main.text.level_info_2.font_header",      "font.text_4"           },
-  { "main.text.level_name.x",                  "-1"                    },
-  { "main.text.level_name.y",                  "-1"                    },
-  { "main.text.level_name.align",              "left"                  },
-  { "main.text.level_name.valign",             "top"                   },
-  { "main.text.level_name.chars",              "-1"                    },
-  { "main.text.level_name.font",               "font.text_2"           },
-  { "main.text.level_author.x",                        "-1"                    },
-  { "main.text.level_author.y",                        "-1"                    },
-  { "main.text.level_author.align",            "left"                  },
-  { "main.text.level_author.valign",           "top"                   },
-  { "main.text.level_author.chars",            "-1"                    },
-  { "main.text.level_author.font",             "font.text_2"           },
-  { "main.text.level_year.x",                  "-1"                    },
-  { "main.text.level_year.y",                  "-1"                    },
-  { "main.text.level_year.align",              "left"                  },
-  { "main.text.level_year.valign",             "top"                   },
-  { "main.text.level_year.digits",             "-1"                    },
-  { "main.text.level_year.font",               "font.text_2"           },
-  { "main.text.level_imported_from.x",         "-1"                    },
-  { "main.text.level_imported_from.y",         "-1"                    },
-  { "main.text.level_imported_from.align",     "left"                  },
-  { "main.text.level_imported_from.valign",    "top"                   },
-  { "main.text.level_imported_from.chars",     "-1"                    },
-  { "main.text.level_imported_from.font",      "font.text_2"           },
-  { "main.text.level_imported_by.x",           "-1"                    },
-  { "main.text.level_imported_by.y",           "-1"                    },
-  { "main.text.level_imported_by.align",       "left"                  },
-  { "main.text.level_imported_by.valign",      "top"                   },
-  { "main.text.level_imported_by.chars",       "-1"                    },
-  { "main.text.level_imported_by.font",                "font.text_2"           },
-  { "main.text.level_tested_by.x",             "-1"                    },
-  { "main.text.level_tested_by.y",             "-1"                    },
-  { "main.text.level_tested_by.align",         "left"                  },
-  { "main.text.level_tested_by.valign",                "top"                   },
-  { "main.text.level_tested_by.chars",         "-1"                    },
-  { "main.text.level_tested_by.font",          "font.text_2"           },
-  { "main.text.title_1.x",                     "272"                   },
-  { "main.text.title_1.y",                     "8"                     },
-  { "main.text.title_1.align",                 "center"                },
-  { "main.text.title_1.valign",                        "top"                   },
-  { "main.text.title_1.font",                  "font.title_1"          },
-  { "main.text.title_2.x",                     "272"                   },
-  { "main.text.title_2.y",                     "46"                    },
-  { "main.text.title_2.align",                 "center"                },
-  { "main.text.title_2.valign",                        "top"                   },
-  { "main.text.title_2.font",                  "font.title_2"          },
-  { "main.text.title_3.x",                     "272"                   },
-  { "main.text.title_3.y",                     "326"                   },
-  { "main.text.title_3.align",                 "center"                },
-  { "main.text.title_3.valign",                        "top"                   },
-  { "main.text.title_3.font",                  "font.title_2"          },
-
-  { "main.input.name.x",                       "-1"                    },
-  { "main.input.name.y",                       "-1"                    },
-  { "main.input.name.align",                   "left"                  },
-  { "main.input.name.valign",                  "top"                   },
-  { "main.input.name.font",                    "font.input_1"          },
-
-  { "main.network_players.x",                  "68"                    },
-  { "main.network_players.y",                  "448"                   },
-  { "main.network_players.align",              "center"                },
-  { "main.network_players.valign",             "middle"                },
-  { "main.network_players.font",               "font.main.network_players" },
-  { "main.network_players.tile_size",          "16"                    },
-  { "main.network_players.border_size",                "2"                     },
-
-  { "main.preview_players.x",                  "474"                   },
-  { "main.preview_players.y",                  "448"                   },
-  { "main.preview_players.align",              "center"                },
-  { "main.preview_players.valign",             "middle"                },
-  { "main.preview_players.tile_size",          "32"                    },
-  { "main.preview_players.border_size",                "2"                     },
-  { "main.preview_players.vertical",           "false"                 },
-  { "main.preview_players.xoffset",            "-1"                    },
-  { "main.preview_players.yoffset",            "-1"                    },
-
-  { "setup.button.prev_player.x",              "320"                   },
-  { "setup.button.prev_player.y",              "64"                    },
-  { "setup.button.next_player.x",              "384"                   },
-  { "setup.button.next_player.y",              "64"                    },
-
-  { "setup.button.touch_back.x",               "0"                     },
-  { "setup.button.touch_back.y",               "0"                     },
-  { "setup.button.touch_next.x",               "-60"                   },
-  { "setup.button.touch_next.y",               "0"                     },
-  { "setup.button.touch_back2.x",              "0"                     },
-  { "setup.button.touch_back2.y",              "-60"                   },
-  { "setup.button.touch_next2.x",              "-60"                   },
-  { "setup.button.touch_next2.y",              "-60"                   },
-
-  { "preview.x",                               "272"                   },
-  { "preview.y",                               "380"                   },
-  { "preview.align",                           "center"                },
-  { "preview.valign",                          "top"                   },
-  { "preview.xsize",                           "66"                    },
-  { "preview.ysize",                           "34"                    },
-  { "preview.xoffset",                         "0"                     },
-  { "preview.yoffset",                         "0"                     },
-  { "preview.tile_size",                       "4"                     },
-  { "preview.step_offset",                     "1"                     },
-  { "preview.step_delay",                      "50"                    },
-  { "preview.anim_mode",                       "default"               },
-
-  { "door_1.part_1.x",                         "0"                     },
-  { "door_1.part_1.y",                         "0"                     },
-  { "door_1.part_1.step_xoffset",              "3"                     },
-  { "door_1.part_1.step_yoffset",              "1"                     },
-  { "door_1.part_1.step_delay",                        "10"                    },
-  { "door_1.part_1.start_step",                        "0"                     },
-  { "door_1.part_1.start_step_opening",                "0"                     },
-  { "door_1.part_1.start_step_closing",                "0"                     },
-  { "door_1.part_1.draw_masked",               "true"                  },
-  { "door_1.part_1.draw_order",                        "3"                     },
-  { "door_1.part_2.x",                         "0"                     },
-  { "door_1.part_2.y",                         "77"                    },
-  { "door_1.part_2.step_xoffset",              "3"                     },
-  { "door_1.part_2.step_yoffset",              "1"                     },
-  { "door_1.part_2.step_delay",                        "10"                    },
-  { "door_1.part_2.start_step",                        "0"                     },
-  { "door_1.part_2.start_step_opening",                "0"                     },
-  { "door_1.part_2.start_step_closing",                "0"                     },
-  { "door_1.part_2.draw_masked",               "true"                  },
-  { "door_1.part_2.draw_order",                        "5"                     },
-  { "door_1.part_3.x",                         "0"                     },
-  { "door_1.part_3.y",                         "140"                   },
-  { "door_1.part_3.step_xoffset",              "3"                     },
-  { "door_1.part_3.step_yoffset",              "1"                     },
-  { "door_1.part_3.step_delay",                        "10"                    },
-  { "door_1.part_3.start_step",                        "0"                     },
-  { "door_1.part_3.start_step_opening",                "0"                     },
-  { "door_1.part_3.start_step_closing",                "0"                     },
-  { "door_1.part_3.draw_masked",               "true"                  },
-  { "door_1.part_3.draw_order",                        "4"                     },
-  { "door_1.part_4.x",                         "0"                     },
-  { "door_1.part_4.y",                         "203"                   },
-  { "door_1.part_4.step_xoffset",              "3"                     },
-  { "door_1.part_4.step_yoffset",              "1"                     },
-  { "door_1.part_4.step_delay",                        "10"                    },
-  { "door_1.part_4.start_step",                        "0"                     },
-  { "door_1.part_4.start_step_opening",                "0"                     },
-  { "door_1.part_4.start_step_closing",                "0"                     },
-  { "door_1.part_4.draw_masked",               "true"                  },
-  { "door_1.part_4.draw_order",                        "6"                     },
-  { "door_1.part_5.x",                         "0"                     },
-  { "door_1.part_5.y",                         "0"                     },
-  { "door_1.part_5.step_xoffset",              "-3"                    },
-  { "door_1.part_5.step_yoffset",              "-1"                    },
-  { "door_1.part_5.step_delay",                        "10"                    },
-  { "door_1.part_5.start_step",                        "0"                     },
-  { "door_1.part_5.start_step_opening",                "0"                     },
-  { "door_1.part_5.start_step_closing",                "0"                     },
-  { "door_1.part_5.draw_masked",               "true"                  },
-  { "door_1.part_5.draw_order",                        "1"                     },
-  { "door_1.part_6.x",                         "0"                     },
-  { "door_1.part_6.y",                         "77"                    },
-  { "door_1.part_6.step_xoffset",              "-3"                    },
-  { "door_1.part_6.step_yoffset",              "-1"                    },
-  { "door_1.part_6.step_delay",                        "10"                    },
-  { "door_1.part_6.start_step",                        "0"                     },
-  { "door_1.part_6.start_step_opening",                "0"                     },
-  { "door_1.part_6.start_step_closing",                "0"                     },
-  { "door_1.part_6.draw_masked",               "true"                  },
-  { "door_1.part_6.draw_order",                        "7"                     },
-  { "door_1.part_7.x",                         "0"                     },
-  { "door_1.part_7.y",                         "140"                   },
-  { "door_1.part_7.step_xoffset",              "-3"                    },
-  { "door_1.part_7.step_yoffset",              "-1"                    },
-  { "door_1.part_7.step_delay",                        "10"                    },
-  { "door_1.part_7.start_step",                        "0"                     },
-  { "door_1.part_7.start_step_opening",                "0"                     },
-  { "door_1.part_7.start_step_closing",                "0"                     },
-  { "door_1.part_7.draw_masked",               "true"                  },
-  { "door_1.part_7.draw_order",                        "2"                     },
-  { "door_1.part_8.x",                         "0"                     },
-  { "door_1.part_8.y",                         "203"                   },
-  { "door_1.part_8.step_xoffset",              "-3"                    },
-  { "door_1.part_8.step_yoffset",              "-1"                    },
-  { "door_1.part_8.step_delay",                        "10"                    },
-  { "door_1.part_8.start_step",                        "0"                     },
-  { "door_1.part_8.start_step_opening",                "0"                     },
-  { "door_1.part_8.start_step_closing",                "0"                     },
-  { "door_1.part_8.draw_masked",               "true"                  },
-  { "door_1.part_8.draw_order",                        "8"                     },
-
-  { "door_2.part_1.x",                         "0"                     },
-  { "door_2.part_1.y",                         "0"                     },
-  { "door_2.part_1.step_xoffset",              "3"                     },
-  { "door_2.part_1.step_yoffset",              "1"                     },
-  { "door_2.part_1.step_delay",                        "10"                    },
-  { "door_2.part_1.start_step",                        "0"                     },
-  { "door_2.part_1.start_step_opening",                "0"                     },
-  { "door_2.part_1.start_step_closing",                "0"                     },
-  { "door_2.part_1.draw_masked",               "true"                  },
-  { "door_2.part_1.draw_order",                        "2"                     },
-  { "door_2.part_2.x",                         "0"                     },
-  { "door_2.part_2.y",                         "50"                    },
-  { "door_2.part_2.step_xoffset",              "3"                     },
-  { "door_2.part_2.step_yoffset",              "1"                     },
-  { "door_2.part_2.step_delay",                        "10"                    },
-  { "door_2.part_2.start_step",                        "0"                     },
-  { "door_2.part_2.start_step_opening",                "0"                     },
-  { "door_2.part_2.start_step_closing",                "0"                     },
-  { "door_2.part_2.draw_masked",               "true"                  },
-  { "door_2.part_2.draw_order",                        "3"                     },
-  { "door_2.part_3.x",                         "0"                     },
-  { "door_2.part_3.y",                         "0"                     },
-  { "door_2.part_3.step_xoffset",              "-3"                    },
-  { "door_2.part_3.step_yoffset",              "-1"                    },
-  { "door_2.part_3.step_delay",                        "10"                    },
-  { "door_2.part_3.start_step",                        "0"                     },
-  { "door_2.part_3.start_step_opening",                "0"                     },
-  { "door_2.part_3.start_step_closing",                "0"                     },
-  { "door_2.part_3.draw_masked",               "true"                  },
-  { "door_2.part_3.draw_order",                        "1"                     },
-  { "door_2.part_4.x",                         "0"                     },
-  { "door_2.part_4.y",                         "50"                    },
-  { "door_2.part_4.step_xoffset",              "-3"                    },
-  { "door_2.part_4.step_yoffset",              "-1"                    },
-  { "door_2.part_4.step_delay",                        "10"                    },
-  { "door_2.part_4.start_step",                        "0"                     },
-  { "door_2.part_4.start_step_opening",                "0"                     },
-  { "door_2.part_4.start_step_closing",                "0"                     },
-  { "door_2.part_4.draw_masked",               "true"                  },
-  { "door_2.part_4.draw_order",                        "4"                     },
-  { "door_2.part_5.x",                         "-1"                    },
-  { "door_2.part_5.y",                         "-1"                    },
-  { "door_2.part_5.step_xoffset",              "0"                     },
-  { "door_2.part_5.step_yoffset",              "0"                     },
-  { "door_2.part_5.step_delay",                        "0"                     },
-  { "door_2.part_5.start_step",                        "0"                     },
-  { "door_2.part_5.start_step_opening",                "0"                     },
-  { "door_2.part_5.start_step_closing",                "0"                     },
-  { "door_2.part_5.draw_masked",               "true"                  },
-  { "door_2.part_5.draw_order",                        "0"                     },
-  { "door_2.part_6.x",                         "-1"                    },
-  { "door_2.part_6.y",                         "-1"                    },
-  { "door_2.part_6.step_xoffset",              "0"                     },
-  { "door_2.part_6.step_yoffset",              "0"                     },
-  { "door_2.part_6.step_delay",                        "0"                     },
-  { "door_2.part_6.start_step",                        "0"                     },
-  { "door_2.part_6.start_step_opening",                "0"                     },
-  { "door_2.part_6.start_step_closing",                "0"                     },
-  { "door_2.part_6.draw_masked",               "true"                  },
-  { "door_2.part_6.draw_order",                        "0"                     },
-  { "door_2.part_7.x",                         "-1"                    },
-  { "door_2.part_7.y",                         "-1"                    },
-  { "door_2.part_7.step_xoffset",              "0"                     },
-  { "door_2.part_7.step_yoffset",              "0"                     },
-  { "door_2.part_7.step_delay",                        "0"                     },
-  { "door_2.part_7.start_step",                        "0"                     },
-  { "door_2.part_7.start_step_opening",                "0"                     },
-  { "door_2.part_7.start_step_closing",                "0"                     },
-  { "door_2.part_7.draw_masked",               "true"                  },
-  { "door_2.part_7.draw_order",                        "0"                     },
-  { "door_2.part_8.x",                         "-1"                    },
-  { "door_2.part_8.y",                         "-1"                    },
-  { "door_2.part_8.step_xoffset",              "0"                     },
-  { "door_2.part_8.step_yoffset",              "0"                     },
-  { "door_2.part_8.step_delay",                        "0"                     },
-  { "door_2.part_8.start_step",                        "0"                     },
-  { "door_2.part_8.start_step_opening",                "0"                     },
-  { "door_2.part_8.start_step_closing",                "0"                     },
-  { "door_2.part_8.draw_masked",               "true"                  },
-  { "door_2.part_8.draw_order",                        "0"                     },
-
-  { "door_1.panel.x",                          "0"                     },
-  { "door_1.panel.y",                          "0"                     },
-  { "door_1.panel.step_xoffset",               "0"                     },
-  { "door_1.panel.step_yoffset",               "1"                     },
-  { "door_1.panel.step_delay",                 "10"                    },
-  { "door_1.panel.start_step",                 "246"                   },
-  { "door_1.panel.start_step_opening",         "0"                     },
-  { "door_1.panel.start_step_closing",         "0"                     },
-  { "door_1.panel.draw_masked",                        "false"                 },
-  { "door_1.panel.draw_order",                 "0"                     },
-
-  { "door_2.panel.x",                          "0"                     },
-  { "door_2.panel.y",                          "0"                     },
-  { "door_2.panel.step_xoffset",               "0"                     },
-  { "door_2.panel.step_yoffset",               "1"                     },
-  { "door_2.panel.step_delay",                 "10"                    },
-  { "door_2.panel.start_step",                 "66"                    },
-  { "door_2.panel.start_step_opening",         "0"                     },
-  { "door_2.panel.start_step_closing",         "0"                     },
-  { "door_2.panel.draw_masked",                        "false"                 },
-  { "door_2.panel.draw_order",                 "0"                     },
-
-  { "door_1.width",                            "-1"                    },
-  { "door_1.height",                           "-1"                    },
-  { "door_1.step_offset",                      "2"                     },
-  { "door_1.step_delay",                       "10"                    },
-  { "door_1.post_delay",                       "100"                   },
-  { "door_1.anim_mode",                                "default"               },
-
-  { "door_2.width",                            "-1"                    },
-  { "door_2.height",                           "-1"                    },
-  { "door_2.step_offset",                      "2"                     },
-  { "door_2.step_delay",                       "10"                    },
-  { "door_2.post_delay",                       "100"                   },
-  { "door_2.anim_mode",                                "default"               },
-
-  { "game.panel.level_number.x",               "51"                    },
-  { "game.panel.level_number.y",               "20"                    },
-  { "game.panel.level_number.align",           "center"                },
-  { "game.panel.level_number.valign",          "top"                   },
-  { "game.panel.level_number.digits",          "-1"                    },
-  { "game.panel.level_number.font",            "font.text_2"           },
-  { "game.panel.level_number.font_narrow",     "font.text_1"           },
-  { "game.panel.level_number.draw_masked",     "true"                  },
-  { "game.panel.level_number.draw_order",      "0"                     },
-  { "game.panel.level_number.class",           "none"                  },
-  { "game.panel.level_number.style",           "none"                  },
-
-  { "game.panel.gems.x",                       "50"                    },
-  { "game.panel.gems.y",                       "54"                    },
-  { "game.panel.gems.align",                   "center"                },
-  { "game.panel.gems.valign",                  "top"                   },
-  { "game.panel.gems.digits",                  "3"                     },
-  { "game.panel.gems.font",                    "font.text_2"           },
-  { "game.panel.gems.draw_masked",             "true"                  },
-  { "game.panel.gems.draw_order",              "0"                     },
-  { "game.panel.gems.class",                   "none"                  },
-  { "game.panel.gems.style",                   "none"                  },
-
-  { "game.panel.inventory_count.x",            "50"                    },
-  { "game.panel.inventory_count.y",            "89"                    },
-  { "game.panel.inventory_count.align",                "center"                },
-  { "game.panel.inventory_count.valign",       "top"                   },
-  { "game.panel.inventory_count.digits",       "3"                     },
-  { "game.panel.inventory_count.font",         "font.text_2"           },
-  { "game.panel.inventory_count.draw_masked",  "true"                  },
-  { "game.panel.inventory_count.draw_order",   "0"                     },
-  { "game.panel.inventory_count.class",                "none"                  },
-  { "game.panel.inventory_count.style",                "none"                  },
-
-  { "game.panel.inventory_first_1.x",          "-1"                    },
-  { "game.panel.inventory_first_1.y",          "-1"                    },
-  { "game.panel.inventory_first_1.tile_size",  "16"                    },
-  { "game.panel.inventory_first_1.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_1.draw_order", "0"                     },
-  { "game.panel.inventory_first_1.class",      "none"                  },
-  { "game.panel.inventory_first_1.style",      "none"                  },
-  { "game.panel.inventory_first_2.x",          "-1"                    },
-  { "game.panel.inventory_first_2.y",          "-1"                    },
-  { "game.panel.inventory_first_2.tile_size",  "16"                    },
-  { "game.panel.inventory_first_2.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_2.draw_order", "0"                     },
-  { "game.panel.inventory_first_2.class",      "none"                  },
-  { "game.panel.inventory_first_2.style",      "none"                  },
-  { "game.panel.inventory_first_3.x",          "-1"                    },
-  { "game.panel.inventory_first_3.y",          "-1"                    },
-  { "game.panel.inventory_first_3.tile_size",  "16"                    },
-  { "game.panel.inventory_first_3.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_3.draw_order", "0"                     },
-  { "game.panel.inventory_first_3.class",      "none"                  },
-  { "game.panel.inventory_first_3.style",      "none"                  },
-  { "game.panel.inventory_first_4.x",          "-1"                    },
-  { "game.panel.inventory_first_4.y",          "-1"                    },
-  { "game.panel.inventory_first_4.tile_size",  "16"                    },
-  { "game.panel.inventory_first_4.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_4.draw_order", "0"                     },
-  { "game.panel.inventory_first_4.class",      "none"                  },
-  { "game.panel.inventory_first_4.style",      "none"                  },
-  { "game.panel.inventory_first_5.x",          "-1"                    },
-  { "game.panel.inventory_first_5.y",          "-1"                    },
-  { "game.panel.inventory_first_5.tile_size",  "16"                    },
-  { "game.panel.inventory_first_5.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_5.draw_order", "0"                     },
-  { "game.panel.inventory_first_5.class",      "none"                  },
-  { "game.panel.inventory_first_5.style",      "none"                  },
-  { "game.panel.inventory_first_6.x",          "-1"                    },
-  { "game.panel.inventory_first_6.y",          "-1"                    },
-  { "game.panel.inventory_first_6.tile_size",  "16"                    },
-  { "game.panel.inventory_first_6.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_6.draw_order", "0"                     },
-  { "game.panel.inventory_first_6.class",      "none"                  },
-  { "game.panel.inventory_first_6.style",      "none"                  },
-  { "game.panel.inventory_first_7.x",          "-1"                    },
-  { "game.panel.inventory_first_7.y",          "-1"                    },
-  { "game.panel.inventory_first_7.tile_size",  "16"                    },
-  { "game.panel.inventory_first_7.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_7.draw_order", "0"                     },
-  { "game.panel.inventory_first_7.class",      "none"                  },
-  { "game.panel.inventory_first_7.style",      "none"                  },
-  { "game.panel.inventory_first_8.x",          "-1"                    },
-  { "game.panel.inventory_first_8.y",          "-1"                    },
-  { "game.panel.inventory_first_8.tile_size",  "16"                    },
-  { "game.panel.inventory_first_8.draw_masked",        "false"                 },
-  { "game.panel.inventory_first_8.draw_order", "0"                     },
-  { "game.panel.inventory_first_8.class",      "none"                  },
-  { "game.panel.inventory_first_8.style",      "none"                  },
-
-  { "game.panel.inventory_last_1.x",           "-1"                    },
-  { "game.panel.inventory_last_1.y",           "-1"                    },
-  { "game.panel.inventory_last_1.tile_size",   "16"                    },
-  { "game.panel.inventory_last_1.draw_masked", "false"                 },
-  { "game.panel.inventory_last_1.draw_order",  "0"                     },
-  { "game.panel.inventory_last_1.class",       "none"                  },
-  { "game.panel.inventory_last_1.style",       "none"                  },
-  { "game.panel.inventory_last_2.x",           "-1"                    },
-  { "game.panel.inventory_last_2.y",           "-1"                    },
-  { "game.panel.inventory_last_2.tile_size",   "16"                    },
-  { "game.panel.inventory_last_2.draw_masked", "false"                 },
-  { "game.panel.inventory_last_2.draw_order",  "0"                     },
-  { "game.panel.inventory_last_2.class",       "none"                  },
-  { "game.panel.inventory_last_2.style",       "none"                  },
-  { "game.panel.inventory_last_3.x",           "-1"                    },
-  { "game.panel.inventory_last_3.y",           "-1"                    },
-  { "game.panel.inventory_last_3.tile_size",   "16"                    },
-  { "game.panel.inventory_last_3.draw_masked", "false"                 },
-  { "game.panel.inventory_last_3.draw_order",  "0"                     },
-  { "game.panel.inventory_last_3.class",       "none"                  },
-  { "game.panel.inventory_last_3.style",       "none"                  },
-  { "game.panel.inventory_last_4.x",           "-1"                    },
-  { "game.panel.inventory_last_4.y",           "-1"                    },
-  { "game.panel.inventory_last_4.tile_size",   "16"                    },
-  { "game.panel.inventory_last_4.draw_masked", "false"                 },
-  { "game.panel.inventory_last_4.draw_order",  "0"                     },
-  { "game.panel.inventory_last_4.class",       "none"                  },
-  { "game.panel.inventory_last_4.style",       "none"                  },
-  { "game.panel.inventory_last_5.x",           "-1"                    },
-  { "game.panel.inventory_last_5.y",           "-1"                    },
-  { "game.panel.inventory_last_5.tile_size",   "16"                    },
-  { "game.panel.inventory_last_5.draw_masked", "false"                 },
-  { "game.panel.inventory_last_5.draw_order",  "0"                     },
-  { "game.panel.inventory_last_5.class",       "none"                  },
-  { "game.panel.inventory_last_5.style",       "none"                  },
-  { "game.panel.inventory_last_6.x",           "-1"                    },
-  { "game.panel.inventory_last_6.y",           "-1"                    },
-  { "game.panel.inventory_last_6.tile_size",   "16"                    },
-  { "game.panel.inventory_last_6.draw_masked", "false"                 },
-  { "game.panel.inventory_last_6.draw_order",  "0"                     },
-  { "game.panel.inventory_last_6.class",       "none"                  },
-  { "game.panel.inventory_last_6.style",       "none"                  },
-  { "game.panel.inventory_last_7.x",           "-1"                    },
-  { "game.panel.inventory_last_7.y",           "-1"                    },
-  { "game.panel.inventory_last_7.tile_size",   "16"                    },
-  { "game.panel.inventory_last_7.draw_masked", "false"                 },
-  { "game.panel.inventory_last_7.draw_order",  "0"                     },
-  { "game.panel.inventory_last_7.class",       "none"                  },
-  { "game.panel.inventory_last_7.style",       "none"                  },
-  { "game.panel.inventory_last_8.x",           "-1"                    },
-  { "game.panel.inventory_last_8.y",           "-1"                    },
-  { "game.panel.inventory_last_8.tile_size",   "16"                    },
-  { "game.panel.inventory_last_8.draw_masked", "false"                 },
-  { "game.panel.inventory_last_8.draw_order",  "0"                     },
-  { "game.panel.inventory_last_8.class",       "none"                  },
-  { "game.panel.inventory_last_8.style",       "none"                  },
-
-  { "game.panel.key_1.x",                      "18"                    },
-  { "game.panel.key_1.y",                      "123"                   },
-  { "game.panel.key_1.tile_size",              "16"                    },
-  { "game.panel.key_1.draw_masked",            "false"                 },
-  { "game.panel.key_1.draw_order",             "0"                     },
-  { "game.panel.key_1.class",                  "none"                  },
-  { "game.panel.key_1.style",                  "none"                  },
-  { "game.panel.key_2.x",                      "34"                    },
-  { "game.panel.key_2.y",                      "123"                   },
-  { "game.panel.key_2.tile_size",              "16"                    },
-  { "game.panel.key_2.draw_masked",            "false"                 },
-  { "game.panel.key_2.draw_order",             "0"                     },
-  { "game.panel.key_2.class",                  "none"                  },
-  { "game.panel.key_2.style",                  "none"                  },
-  { "game.panel.key_3.x",                      "50"                    },
-  { "game.panel.key_3.y",                      "123"                   },
-  { "game.panel.key_3.tile_size",              "16"                    },
-  { "game.panel.key_3.draw_masked",            "false"                 },
-  { "game.panel.key_3.draw_order",             "0"                     },
-  { "game.panel.key_3.class",                  "none"                  },
-  { "game.panel.key_3.style",                  "none"                  },
-  { "game.panel.key_4.x",                      "66"                    },
-  { "game.panel.key_4.y",                      "123"                   },
-  { "game.panel.key_4.tile_size",              "16"                    },
-  { "game.panel.key_4.draw_masked",            "false"                 },
-  { "game.panel.key_4.draw_order",             "0"                     },
-  { "game.panel.key_4.class",                  "none"                  },
-  { "game.panel.key_4.style",                  "none"                  },
-  { "game.panel.key_5.x",                      "-1"                    },
-  { "game.panel.key_5.y",                      "-1"                    },
-  { "game.panel.key_5.tile_size",              "16"                    },
-  { "game.panel.key_5.draw_masked",            "false"                 },
-  { "game.panel.key_5.draw_order",             "0"                     },
-  { "game.panel.key_5.class",                  "none"                  },
-  { "game.panel.key_5.style",                  "none"                  },
-  { "game.panel.key_6.x",                      "-1"                    },
-  { "game.panel.key_6.y",                      "-1"                    },
-  { "game.panel.key_6.tile_size",              "16"                    },
-  { "game.panel.key_6.draw_masked",            "false"                 },
-  { "game.panel.key_6.draw_order",             "0"                     },
-  { "game.panel.key_6.class",                  "none"                  },
-  { "game.panel.key_6.style",                  "none"                  },
-  { "game.panel.key_7.x",                      "-1"                    },
-  { "game.panel.key_7.y",                      "-1"                    },
-  { "game.panel.key_7.tile_size",              "16"                    },
-  { "game.panel.key_7.draw_masked",            "false"                 },
-  { "game.panel.key_7.draw_order",             "0"                     },
-  { "game.panel.key_7.class",                  "none"                  },
-  { "game.panel.key_7.style",                  "none"                  },
-  { "game.panel.key_8.x",                      "-1"                    },
-  { "game.panel.key_8.y",                      "-1"                    },
-  { "game.panel.key_8.tile_size",              "16"                    },
-  { "game.panel.key_8.draw_masked",            "false"                 },
-  { "game.panel.key_8.draw_order",             "0"                     },
-  { "game.panel.key_8.class",                  "none"                  },
-  { "game.panel.key_8.style",                  "none"                  },
-  { "game.panel.key_white.x",                  "-1"                    },
-  { "game.panel.key_white.y",                  "-1"                    },
-  { "game.panel.key_white.tile_size",          "16"                    },
-  { "game.panel.key_white.draw_masked",                "false"                 },
-  { "game.panel.key_white.draw_order",         "0"                     },
-  { "game.panel.key_white.class",              "none"                  },
-  { "game.panel.key_white.style",              "none"                  },
-  { "game.panel.key_white_count.x",            "-1"                    },
-  { "game.panel.key_white_count.y",            "-1"                    },
-  { "game.panel.key_white_count.align",                "left"                  },
-  { "game.panel.key_white_count.valign",       "top"                   },
-  { "game.panel.key_white_count.digits",       "-1"                    },
-  { "game.panel.key_white_count.font",         "font.text_2"           },
-  { "game.panel.key_white_count.draw_masked",  "true"                  },
-  { "game.panel.key_white_count.draw_order",   "0"                     },
-  { "game.panel.key_white_count.class",                "none"                  },
-  { "game.panel.key_white_count.style",                "none"                  },
-
-  { "game.panel.score.x",                      "50"                    },
-  { "game.panel.score.y",                      "159"                   },
-  { "game.panel.score.align",                  "center"                },
-  { "game.panel.score.valign",                 "top"                   },
-  { "game.panel.score.digits",                 "5"                     },
-  { "game.panel.score.font",                   "font.text_2"           },
-  { "game.panel.score.draw_masked",            "true"                  },
-  { "game.panel.score.draw_order",             "0"                     },
-  { "game.panel.score.class",                  "none"                  },
-  { "game.panel.score.style",                  "none"                  },
-
-  { "game.panel.highscore.x",                  "-1"                    },
-  { "game.panel.highscore.y",                  "-1"                    },
-  { "game.panel.highscore.align",              "left"                  },
-  { "game.panel.highscore.valign",             "top"                   },
-  { "game.panel.highscore.digits",             "5"                     },
-  { "game.panel.highscore.font",               "font.text_2"           },
-  { "game.panel.highscore.draw_masked",                "true"                  },
-  { "game.panel.highscore.draw_order",         "0"                     },
-  { "game.panel.highscore.class",              "none"                  },
-  { "game.panel.highscore.style",              "none"                  },
-
-  { "game.panel.time.x",                       "50"                    },
-  { "game.panel.time.y",                       "194"                   },
-  { "game.panel.time.align",                   "center"                },
-  { "game.panel.time.valign",                  "top"                   },
-  { "game.panel.time.digits",                  "-1"                    },
-  { "game.panel.time.font",                    "font.text_2"           },
-  { "game.panel.time.font_narrow",             "font.text_1"           },
-  { "game.panel.time.draw_masked",             "true"                  },
-  { "game.panel.time.draw_order",              "0"                     },
-  { "game.panel.time.class",                   "none"                  },
-  { "game.panel.time.style",                   "none"                  },
-
-  { "game.panel.time_hh.x",                    "-1"                    },
-  { "game.panel.time_hh.y",                    "-1"                    },
-  { "game.panel.time_hh.align",                        "left"                  },
-  { "game.panel.time_hh.valign",               "top"                   },
-  { "game.panel.time_hh.digits",               "2"                     },
-  { "game.panel.time_hh.font",                 "font.text_2"           },
-  { "game.panel.time_hh.draw_masked",          "true"                  },
-  { "game.panel.time_hh.draw_order",           "0"                     },
-  { "game.panel.time_hh.class",                        "none"                  },
-  { "game.panel.time_hh.style",                        "none"                  },
-  { "game.panel.time_mm.x",                    "-1"                    },
-  { "game.panel.time_mm.y",                    "-1"                    },
-  { "game.panel.time_mm.align",                        "left"                  },
-  { "game.panel.time_mm.valign",               "top"                   },
-  { "game.panel.time_mm.digits",               "2"                     },
-  { "game.panel.time_mm.font",                 "font.text_2"           },
-  { "game.panel.time_mm.draw_masked",          "true"                  },
-  { "game.panel.time_mm.draw_order",           "0"                     },
-  { "game.panel.time_mm.class",                        "none"                  },
-  { "game.panel.time_mm.style",                        "none"                  },
-  { "game.panel.time_ss.x",                    "-1"                    },
-  { "game.panel.time_ss.y",                    "-1"                    },
-  { "game.panel.time_ss.align",                        "left"                  },
-  { "game.panel.time_ss.valign",               "top"                   },
-  { "game.panel.time_ss.digits",               "2"                     },
-  { "game.panel.time_ss.font",                 "font.text_2"           },
-  { "game.panel.time_ss.draw_masked",          "true"                  },
-  { "game.panel.time_ss.draw_order",           "0"                     },
-  { "game.panel.time_ss.class",                        "none"                  },
-  { "game.panel.time_ss.style",                        "none"                  },
-
-  { "game.panel.time_anim.x",                  "5"                     },
-  { "game.panel.time_anim.y",                  "72"                    },
-  { "game.panel.time_anim.direction",          "right"                 },
-  { "game.panel.time_anim.class",              "mm_engine_only"        },
-  { "game.panel.time_anim.style",              "none"                  },
-
-  { "game.panel.health.x",                     "-1"                    },
-  { "game.panel.health.y",                     "-1"                    },
-  { "game.panel.health.align",                 "center"                },
-  { "game.panel.health.valign",                        "top"                   },
-  { "game.panel.health.digits",                        "-1"                    },
-  { "game.panel.health.font",                  "font.text_2"           },
-  { "game.panel.health.font_narrow",           "font.text_1"           },
-  { "game.panel.health.draw_masked",           "true"                  },
-  { "game.panel.health.draw_order",            "0"                     },
-  { "game.panel.health.class",                 "none"                  },
-  { "game.panel.health.style",                 "none"                  },
-
-  { "game.panel.health_anim.x",                        "5"                     },
-  { "game.panel.health_anim.y",                        "107"                   },
-  { "game.panel.health_anim.direction",                "right"                 },
-  { "game.panel.health_anim.class",            "mm_engine_only"        },
-  { "game.panel.health_anim.style",            "reverse"               },
-
-  { "game.panel.frame.x",                      "-1"                    },
-  { "game.panel.frame.y",                      "-1"                    },
-  { "game.panel.frame.align",                  "left"                  },
-  { "game.panel.frame.valign",                 "top"                   },
-  { "game.panel.frame.digits",                 "-1"                    },
-  { "game.panel.frame.font",                   "font.text_2"           },
-  { "game.panel.frame.draw_masked",            "true"                  },
-  { "game.panel.frame.draw_order",             "0"                     },
-  { "game.panel.frame.class",                  "none"                  },
-  { "game.panel.frame.style",                  "none"                  },
-
-  { "game.panel.shield_normal.x",              "-1"                    },
-  { "game.panel.shield_normal.y",              "-1"                    },
-  { "game.panel.shield_normal.tile_size",      "16"                    },
-  { "game.panel.shield_normal.draw_masked",    "false"                 },
-  { "game.panel.shield_normal.draw_order",     "0"                     },
-  { "game.panel.shield_normal_time.x",         "-1"                    },
-  { "game.panel.shield_normal_time.y",         "-1"                    },
-  { "game.panel.shield_normal_time.align",     "left"                  },
-  { "game.panel.shield_normal_time.valign",    "top"                   },
-  { "game.panel.shield_normal_time.digits",    "-1"                    },
-  { "game.panel.shield_normal_time.font",      "font.text_2"           },
-  { "game.panel.shield_normal_time.draw_masked", "true"                        },
-  { "game.panel.shield_normal_time.draw_order",        "0"                     },
-  { "game.panel.shield_normal_time.class",     "none"                  },
-  { "game.panel.shield_normal_time.style",     "none"                  },
-  { "game.panel.shield_deadly.x",              "-1"                    },
-  { "game.panel.shield_deadly.y",              "-1"                    },
-  { "game.panel.shield_deadly.tile_size",      "16"                    },
-  { "game.panel.shield_deadly.draw_masked",    "false"                 },
-  { "game.panel.shield_deadly.draw_order",     "0"                     },
-  { "game.panel.shield_deadly_time.x",         "-1"                    },
-  { "game.panel.shield_deadly_time.y",         "-1"                    },
-  { "game.panel.shield_deadly_time.align",     "left"                  },
-  { "game.panel.shield_deadly_time.valign",    "top"                   },
-  { "game.panel.shield_deadly_time.digits",    "-1"                    },
-  { "game.panel.shield_deadly_time.font",      "font.text_2"           },
-  { "game.panel.shield_deadly_time.draw_masked","true"                 },
-  { "game.panel.shield_deadly_time.draw_order",        "0"                     },
-  { "game.panel.shield_deadly_time.class",     "none"                  },
-  { "game.panel.shield_deadly_time.style",     "none"                  },
-
-  { "game.panel.exit.x",                       "-1"                    },
-  { "game.panel.exit.y",                       "-1"                    },
-  { "game.panel.exit.tile_size",               "16"                    },
-  { "game.panel.exit.draw_masked",             "false"                 },
-  { "game.panel.exit.draw_order",              "0"                     },
-  { "game.panel.exit.class",                   "none"                  },
-  { "game.panel.exit.style",                   "none"                  },
-
-  { "game.panel.emc_magic_ball.x",             "-1"                    },
-  { "game.panel.emc_magic_ball.y",             "-1"                    },
-  { "game.panel.emc_magic_ball.tile_size",     "16"                    },
-  { "game.panel.emc_magic_ball.draw_masked",   "false"                 },
-  { "game.panel.emc_magic_ball.draw_order",    "0"                     },
-  { "game.panel.emc_magic_ball_switch.x",      "-1"                    },
-  { "game.panel.emc_magic_ball_switch.y",      "-1"                    },
-  { "game.panel.emc_magic_ball_switch.tile_size", "16"                 },
-  { "game.panel.emc_magic_ball_switch.draw_masked", "true"             },
-  { "game.panel.emc_magic_ball_switch.draw_order", "0"                 },
-  { "game.panel.emc_magic_ball_switch.class",  "none"                  },
-  { "game.panel.emc_magic_ball_switch.style",  "none"                  },
-
-  { "game.panel.light_switch.x",               "-1"                    },
-  { "game.panel.light_switch.y",               "-1"                    },
-  { "game.panel.light_switch.tile_size",       "16"                    },
-  { "game.panel.light_switch.draw_masked",     "false"                 },
-  { "game.panel.light_switch.draw_order",      "0"                     },
-  { "game.panel.light_switch_time.x",          "-1"                    },
-  { "game.panel.light_switch_time.y",          "-1"                    },
-  { "game.panel.light_switch_time.align",      "left"                  },
-  { "game.panel.light_switch_time.valign",     "top"                   },
-  { "game.panel.light_switch_time.digits",     "-1"                    },
-  { "game.panel.light_switch_time.font",       "font.text_2"           },
-  { "game.panel.light_switch_time.draw_masked",        "true"                  },
-  { "game.panel.light_switch_time.draw_order", "0"                     },
-  { "game.panel.light_switch_time.class",      "none"                  },
-  { "game.panel.light_switch_time.style",      "none"                  },
-
-  { "game.panel.timegate_switch.x",            "-1"                    },
-  { "game.panel.timegate_switch.y",            "-1"                    },
-  { "game.panel.timegate_switch.tile_size",    "16"                    },
-  { "game.panel.timegate_switch.draw_masked",  "false"                 },
-  { "game.panel.timegate_switch.draw_order",   "0"                     },
-  { "game.panel.timegate_switch_time.x",       "-1"                    },
-  { "game.panel.timegate_switch_time.y",       "-1"                    },
-  { "game.panel.timegate_switch_time.align",   "left"                  },
-  { "game.panel.timegate_switch_time.valign",  "top"                   },
-  { "game.panel.timegate_switch_time.digits",  "-1"                    },
-  { "game.panel.timegate_switch_time.font",    "font.text_2"           },
-  { "game.panel.timegate_switch_time.draw_masked", "true"              },
-  { "game.panel.timegate_switch_time.draw_order", "0"                  },
-  { "game.panel.timegate_switch_time.class",   "none"                  },
-  { "game.panel.timegate_switch_time.style",   "none"                  },
-
-  { "game.panel.switchgate_switch.x",          "-1"                    },
-  { "game.panel.switchgate_switch.y",          "-1"                    },
-  { "game.panel.switchgate_switch.tile_size",  "16"                    },
-  { "game.panel.switchgate_switch.draw_masked",        "false"                 },
-  { "game.panel.switchgate_switch.draw_order", "0"                     },
-  { "game.panel.switchgate_switch.class",      "none"                  },
-  { "game.panel.switchgate_switch.style",      "none"                  },
-
-  { "game.panel.emc_lenses.x",                 "-1"                    },
-  { "game.panel.emc_lenses.y",                 "-1"                    },
-  { "game.panel.emc_lenses.tile_size",         "16"                    },
-  { "game.panel.emc_lenses.draw_masked",       "false"                 },
-  { "game.panel.emc_lenses.draw_order",                "0"                     },
-  { "game.panel.emc_lenses.class",             "none"                  },
-  { "game.panel.emc_lenses.style",             "none"                  },
-  { "game.panel.emc_lenses_time.x",            "-1"                    },
-  { "game.panel.emc_lenses_time.y",            "-1"                    },
-  { "game.panel.emc_lenses_time.align",                "left"                  },
-  { "game.panel.emc_lenses_time.valign",       "top"                   },
-  { "game.panel.emc_lenses_time.digits",       "-1"                    },
-  { "game.panel.emc_lenses_time.font",         "font.text_2"           },
-  { "game.panel.emc_lenses_time.draw_masked",  "true"                  },
-  { "game.panel.emc_lenses_time.draw_order",   "0"                     },
-  { "game.panel.emc_lenses_time.class",                "none"                  },
-  { "game.panel.emc_lenses_time.style",                "none"                  },
-
-  { "game.panel.emc_magnifier.x",              "-1"                    },
-  { "game.panel.emc_magnifier.y",              "-1"                    },
-  { "game.panel.emc_magnifier.tile_size",      "16"                    },
-  { "game.panel.emc_magnifier.draw_masked",    "false"                 },
-  { "game.panel.emc_magnifier.draw_order",     "0"                     },
-  { "game.panel.emc_magnifier.class",          "none"                  },
-  { "game.panel.emc_magnifier.style",          "none"                  },
-  { "game.panel.emc_magnifier_time.x",         "-1"                    },
-  { "game.panel.emc_magnifier_time.y",         "-1"                    },
-  { "game.panel.emc_magnifier_time.align",     "left"                  },
-  { "game.panel.emc_magnifier_time.valign",    "top"                   },
-  { "game.panel.emc_magnifier_time.digits",    "-1"                    },
-  { "game.panel.emc_magnifier_time.font",      "font.text_2"           },
-  { "game.panel.emc_magnifier_time.draw_masked","true"                 },
-  { "game.panel.emc_magnifier_time.draw_order",        "0"                     },
-  { "game.panel.emc_magnifier_time.class",     "none"                  },
-  { "game.panel.emc_magnifier_time.style",     "none"                  },
-
-  { "game.panel.balloon_switch.x",             "-1"                    },
-  { "game.panel.balloon_switch.y",             "-1"                    },
-  { "game.panel.balloon_switch.tile_size",     "16"                    },
-  { "game.panel.balloon_switch.draw_masked",   "false"                 },
-  { "game.panel.balloon_switch.draw_order",    "0"                     },
-  { "game.panel.balloon_switch.class",         "none"                  },
-  { "game.panel.balloon_switch.style",         "none"                  },
-
-  { "game.panel.dynabomb_number.x",            "-1"                    },
-  { "game.panel.dynabomb_number.y",            "-1"                    },
-  { "game.panel.dynabomb_number.align",                "left"                  },
-  { "game.panel.dynabomb_number.valign",       "top"                   },
-  { "game.panel.dynabomb_number.digits",       "-1"                    },
-  { "game.panel.dynabomb_number.font",         "font.text_2"           },
-  { "game.panel.dynabomb_number.draw_masked",  "true"                  },
-  { "game.panel.dynabomb_number.draw_order",   "0"                     },
-  { "game.panel.dynabomb_number.class",                "none"                  },
-  { "game.panel.dynabomb_number.style",                "none"                  },
-  { "game.panel.dynabomb_size.x",              "-1"                    },
-  { "game.panel.dynabomb_size.y",              "-1"                    },
-  { "game.panel.dynabomb_size.align",          "left"                  },
-  { "game.panel.dynabomb_size.valign",         "top"                   },
-  { "game.panel.dynabomb_size.digits",         "-1"                    },
-  { "game.panel.dynabomb_size.font",           "font.text_2"           },
-  { "game.panel.dynabomb_size.draw_masked",    "true"                  },
-  { "game.panel.dynabomb_size.draw_order",     "0"                     },
-  { "game.panel.dynabomb_size.class",          "none"                  },
-  { "game.panel.dynabomb_size.style",          "none"                  },
-  { "game.panel.dynabomb_power.x",             "-1"                    },
-  { "game.panel.dynabomb_power.y",             "-1"                    },
-  { "game.panel.dynabomb_power.tile_size",     "16"                    },
-  { "game.panel.dynabomb_power.draw_masked",   "false"                 },
-  { "game.panel.dynabomb_power.draw_order",    "0"                     },
-  { "game.panel.dynabomb_power.class",         "none"                  },
-  { "game.panel.dynabomb_power.style",         "none"                  },
-
-  { "game.panel.penguins.x",                   "-1"                    },
-  { "game.panel.penguins.y",                   "-1"                    },
-  { "game.panel.penguins.align",               "left"                  },
-  { "game.panel.penguins.valign",              "top"                   },
-  { "game.panel.penguins.digits",              "-1"                    },
-  { "game.panel.penguins.font",                        "font.text_2"           },
-  { "game.panel.penguins.draw_masked",         "true"                  },
-  { "game.panel.penguins.draw_order",          "0"                     },
-  { "game.panel.penguins.class",               "none"                  },
-  { "game.panel.penguins.style",               "none"                  },
-
-  { "game.panel.sokoban_objects.x",            "-1"                    },
-  { "game.panel.sokoban_objects.y",            "-1"                    },
-  { "game.panel.sokoban_objects.align",                "left"                  },
-  { "game.panel.sokoban_objects.valign",       "top"                   },
-  { "game.panel.sokoban_objects.digits",       "-1"                    },
-  { "game.panel.sokoban_objects.font",         "font.text_2"           },
-  { "game.panel.sokoban_objects.draw_masked",  "true"                  },
-  { "game.panel.sokoban_objects.draw_order",   "0"                     },
-  { "game.panel.sokoban_objects.class",                "none"                  },
-  { "game.panel.sokoban_objects.style",                "none"                  },
-  { "game.panel.sokoban_fields.x",             "-1"                    },
-  { "game.panel.sokoban_fields.y",             "-1"                    },
-  { "game.panel.sokoban_fields.align",         "left"                  },
-  { "game.panel.sokoban_fields.valign",                "top"                   },
-  { "game.panel.sokoban_fields.digits",                "-1"                    },
-  { "game.panel.sokoban_fields.font",          "font.text_2"           },
-  { "game.panel.sokoban_fields.draw_masked",   "true"                  },
-  { "game.panel.sokoban_fields.draw_order",    "0"                     },
-  { "game.panel.sokoban_fields.class",         "none"                  },
-  { "game.panel.sokoban_fields.style",         "none"                  },
-
-  { "game.panel.robot_wheel.x",                        "-1"                    },
-  { "game.panel.robot_wheel.y",                        "-1"                    },
-  { "game.panel.robot_wheel.tile_size",                "16"                    },
-  { "game.panel.robot_wheel.draw_masked",      "false"                 },
-  { "game.panel.robot_wheel.draw_order",       "0"                     },
-  { "game.panel.robot_wheel.class",            "none"                  },
-  { "game.panel.robot_wheel.style",            "none"                  },
-
-  { "game.panel.conveyor_belt_1.x",            "-1"                    },
-  { "game.panel.conveyor_belt_1.y",            "-1"                    },
-  { "game.panel.conveyor_belt_1.tile_size",    "16"                    },
-  { "game.panel.conveyor_belt_1.draw_masked",  "false"                 },
-  { "game.panel.conveyor_belt_1.draw_order",   "0"                     },
-  { "game.panel.conveyor_belt_1.class",                "none"                  },
-  { "game.panel.conveyor_belt_1.style",                "none"                  },
-  { "game.panel.conveyor_belt_1_switch.x",     "-1"                    },
-  { "game.panel.conveyor_belt_1_switch.y",     "-1"                    },
-  { "game.panel.conveyor_belt_1_switch.tile_size", "16"                        },
-  { "game.panel.conveyor_belt_1_switch.draw_masked", "false"           },
-  { "game.panel.conveyor_belt_1_switch.draw_order", "0"                        },
-  { "game.panel.conveyor_belt_1_switch.class", "none"                  },
-  { "game.panel.conveyor_belt_1_switch.style", "none"                  },
-  { "game.panel.conveyor_belt_2.x",            "-1"                    },
-  { "game.panel.conveyor_belt_2.y",            "-1"                    },
-  { "game.panel.conveyor_belt_2.tile_size",    "16"                    },
-  { "game.panel.conveyor_belt_2.draw_masked",  "false"                 },
-  { "game.panel.conveyor_belt_2.draw_order",   "0"                     },
-  { "game.panel.conveyor_belt_2.class",                "none"                  },
-  { "game.panel.conveyor_belt_2.style",                "none"                  },
-  { "game.panel.conveyor_belt_2_switch.x",     "-1"                    },
-  { "game.panel.conveyor_belt_2_switch.y",     "-1"                    },
-  { "game.panel.conveyor_belt_2_switch.tile_size", "16"                        },
-  { "game.panel.conveyor_belt_2_switch.draw_masked", "false"           },
-  { "game.panel.conveyor_belt_2_switch.draw_order", "0"                        },
-  { "game.panel.conveyor_belt_2_switch.class", "none"                  },
-  { "game.panel.conveyor_belt_2_switch.style", "none"                  },
-  { "game.panel.conveyor_belt_3.x",            "-1"                    },
-  { "game.panel.conveyor_belt_3.y",            "-1"                    },
-  { "game.panel.conveyor_belt_3.tile_size",    "16"                    },
-  { "game.panel.conveyor_belt_3.draw_masked",  "false"                 },
-  { "game.panel.conveyor_belt_3.draw_order",   "0"                     },
-  { "game.panel.conveyor_belt_3.class",                "none"                  },
-  { "game.panel.conveyor_belt_3.style",                "none"                  },
-  { "game.panel.conveyor_belt_3_switch.x",     "-1"                    },
-  { "game.panel.conveyor_belt_3_switch.y",     "-1"                    },
-  { "game.panel.conveyor_belt_3_switch.tile_size", "16"                        },
-  { "game.panel.conveyor_belt_3_switch.draw_masked", "false"           },
-  { "game.panel.conveyor_belt_3_switch.draw_order", "0"                        },
-  { "game.panel.conveyor_belt_3_switch.class", "none"                  },
-  { "game.panel.conveyor_belt_3_switch.style", "none"                  },
-  { "game.panel.conveyor_belt_4.x",            "-1"                    },
-  { "game.panel.conveyor_belt_4.y",            "-1"                    },
-  { "game.panel.conveyor_belt_4.tile_size",    "16"                    },
-  { "game.panel.conveyor_belt_4.draw_masked",  "false"                 },
-  { "game.panel.conveyor_belt_4.draw_order",   "0"                     },
-  { "game.panel.conveyor_belt_4.class",                "none"                  },
-  { "game.panel.conveyor_belt_4.style",                "none"                  },
-  { "game.panel.conveyor_belt_4_switch.x",     "-1"                    },
-  { "game.panel.conveyor_belt_4_switch.y",     "-1"                    },
-  { "game.panel.conveyor_belt_4_switch.tile_size", "16"                        },
-  { "game.panel.conveyor_belt_4_switch.draw_masked", "false"           },
-  { "game.panel.conveyor_belt_4_switch.draw_order", "0"                        },
-  { "game.panel.conveyor_belt_4_switch.class", "none"                  },
-  { "game.panel.conveyor_belt_4_switch.style", "none"                  },
-
-  { "game.panel.magic_wall.x",                 "-1"                    },
-  { "game.panel.magic_wall.y",                 "-1"                    },
-  { "game.panel.magic_wall.tile_size",         "16"                    },
-  { "game.panel.magic_wall.draw_masked",       "false"                 },
-  { "game.panel.magic_wall.draw_order",                "0"                     },
-  { "game.panel.magic_wall.class",             "none"                  },
-  { "game.panel.magic_wall.style",             "none"                  },
-  { "game.panel.magic_wall_time.x",            "-1"                    },
-  { "game.panel.magic_wall_time.y",            "-1"                    },
-  { "game.panel.magic_wall_time.align",                "left"                  },
-  { "game.panel.magic_wall_time.valign",       "top"                   },
-  { "game.panel.magic_wall_time.digits",       "-1"                    },
-  { "game.panel.magic_wall_time.font",         "font.text_2"           },
-  { "game.panel.magic_wall_time.draw_masked",  "true"                  },
-  { "game.panel.magic_wall_time.draw_order",   "0"                     },
-  { "game.panel.magic_wall_time.class",                "none"                  },
-  { "game.panel.magic_wall_time.style",                "none"                  },
-
-  { "game.panel.gravity_state.x",              "-1"                    },
-  { "game.panel.gravity_state.y",              "-1"                    },
-  { "game.panel.gravity_state.align",          "left"                  },
-  { "game.panel.gravity_state.valign",         "top"                   },
-  { "game.panel.gravity_state.chars",          "-1"                    },
-  { "game.panel.gravity_state.font",           "font.text_1"           },
-  { "game.panel.gravity_state.font_active",    "font.text_2"           },
-  { "game.panel.gravity_state.draw_masked",    "true"                  },
-  { "game.panel.gravity_state.draw_order",     "0"                     },
-  { "game.panel.gravity_state.class",          "none"                  },
-  { "game.panel.gravity_state.style",          "none"                  },
-
-  { "game.panel.graphic_1.x",                  "-1"                    },
-  { "game.panel.graphic_1.y",                  "-1"                    },
-  { "game.panel.graphic_1.draw_masked",                "true"                  },
-  { "game.panel.graphic_1.draw_order",         "0"                     },
-  { "game.panel.graphic_1.class",              "none"                  },
-  { "game.panel.graphic_1.style",              "none"                  },
-  { "game.panel.graphic_2.x",                  "-1"                    },
-  { "game.panel.graphic_2.y",                  "-1"                    },
-  { "game.panel.graphic_2.draw_masked",                "true"                  },
-  { "game.panel.graphic_2.draw_order",         "0"                     },
-  { "game.panel.graphic_2.class",              "none"                  },
-  { "game.panel.graphic_2.style",              "none"                  },
-  { "game.panel.graphic_3.x",                  "-1"                    },
-  { "game.panel.graphic_3.y",                  "-1"                    },
-  { "game.panel.graphic_3.draw_masked",                "true"                  },
-  { "game.panel.graphic_3.draw_order",         "0"                     },
-  { "game.panel.graphic_3.class",              "none"                  },
-  { "game.panel.graphic_3.style",              "none"                  },
-  { "game.panel.graphic_4.x",                  "-1"                    },
-  { "game.panel.graphic_4.y",                  "-1"                    },
-  { "game.panel.graphic_4.draw_masked",                "true"                  },
-  { "game.panel.graphic_4.draw_order",         "0"                     },
-  { "game.panel.graphic_4.class",              "none"                  },
-  { "game.panel.graphic_4.style",              "none"                  },
-  { "game.panel.graphic_5.x",                  "-1"                    },
-  { "game.panel.graphic_5.y",                  "-1"                    },
-  { "game.panel.graphic_5.draw_masked",                "true"                  },
-  { "game.panel.graphic_5.draw_order",         "0"                     },
-  { "game.panel.graphic_5.class",              "none"                  },
-  { "game.panel.graphic_5.style",              "none"                  },
-  { "game.panel.graphic_6.x",                  "-1"                    },
-  { "game.panel.graphic_6.y",                  "-1"                    },
-  { "game.panel.graphic_6.draw_masked",                "true"                  },
-  { "game.panel.graphic_6.draw_order",         "0"                     },
-  { "game.panel.graphic_6.class",              "none"                  },
-  { "game.panel.graphic_6.style",              "none"                  },
-  { "game.panel.graphic_7.x",                  "-1"                    },
-  { "game.panel.graphic_7.y",                  "-1"                    },
-  { "game.panel.graphic_7.draw_masked",                "true"                  },
-  { "game.panel.graphic_7.draw_order",         "0"                     },
-  { "game.panel.graphic_7.class",              "none"                  },
-  { "game.panel.graphic_7.style",              "none"                  },
-  { "game.panel.graphic_8.x",                  "-1"                    },
-  { "game.panel.graphic_8.y",                  "-1"                    },
-  { "game.panel.graphic_8.draw_masked",                "true"                  },
-  { "game.panel.graphic_8.draw_order",         "0"                     },
-  { "game.panel.graphic_8.class",              "none"                  },
-  { "game.panel.graphic_8.style",              "none"                  },
-
-  { "game.panel.element_1.x",                  "-1"                    },
-  { "game.panel.element_1.y",                  "-1"                    },
-  { "game.panel.element_1.tile_size",          "16"                    },
-  { "game.panel.element_1.element",            "empty_space"           },
-  { "game.panel.element_1.draw_masked",                "false"                 },
-  { "game.panel.element_1.draw_order",         "0"                     },
-  { "game.panel.element_1.class",              "none"                  },
-  { "game.panel.element_1.style",              "none"                  },
-  { "game.panel.element_1_count.x",            "-1"                    },
-  { "game.panel.element_1_count.y",            "-1"                    },
-  { "game.panel.element_1_count.align",                "left"                  },
-  { "game.panel.element_1_count.valign",       "top"                   },
-  { "game.panel.element_1_count.digits",       "-1"                    },
-  { "game.panel.element_1_count.font",         "font.text_2"           },
-  { "game.panel.element_1_count.element",      "empty_space"           },
-  { "game.panel.element_1_count.draw_masked",  "true"                  },
-  { "game.panel.element_1_count.draw_order",   "0"                     },
-  { "game.panel.element_1_count.class",                "none"                  },
-  { "game.panel.element_1_count.style",                "none"                  },
-  { "game.panel.element_2.x",                  "-1"                    },
-  { "game.panel.element_2.y",                  "-1"                    },
-  { "game.panel.element_2.tile_size",          "16"                    },
-  { "game.panel.element_2.element",            "empty_space"           },
-  { "game.panel.element_2.draw_masked",                "false"                 },
-  { "game.panel.element_2.draw_order",         "0"                     },
-  { "game.panel.element_2.class",              "none"                  },
-  { "game.panel.element_2.style",              "none"                  },
-  { "game.panel.element_2_count.x",            "-1"                    },
-  { "game.panel.element_2_count.y",            "-1"                    },
-  { "game.panel.element_2_count.align",                "left"                  },
-  { "game.panel.element_2_count.valign",       "top"                   },
-  { "game.panel.element_2_count.digits",       "-1"                    },
-  { "game.panel.element_2_count.font",         "font.text_2"           },
-  { "game.panel.element_2_count.element",      "empty_space"           },
-  { "game.panel.element_2_count.draw_masked",  "true"                  },
-  { "game.panel.element_2_count.draw_order",   "0"                     },
-  { "game.panel.element_2_count.class",                "none"                  },
-  { "game.panel.element_2_count.style",                "none"                  },
-  { "game.panel.element_3.x",                  "-1"                    },
-  { "game.panel.element_3.y",                  "-1"                    },
-  { "game.panel.element_3.tile_size",          "16"                    },
-  { "game.panel.element_3.element",            "empty_space"           },
-  { "game.panel.element_3.draw_masked",                "false"                 },
-  { "game.panel.element_3.draw_order",         "0"                     },
-  { "game.panel.element_3.class",              "none"                  },
-  { "game.panel.element_3.style",              "none"                  },
-  { "game.panel.element_3_count.x",            "-1"                    },
-  { "game.panel.element_3_count.y",            "-1"                    },
-  { "game.panel.element_3_count.align",                "left"                  },
-  { "game.panel.element_3_count.valign",       "top"                   },
-  { "game.panel.element_3_count.digits",       "-1"                    },
-  { "game.panel.element_3_count.font",         "font.text_2"           },
-  { "game.panel.element_3_count.element",      "empty_space"           },
-  { "game.panel.element_3_count.draw_masked",  "true"                  },
-  { "game.panel.element_3_count.draw_order",   "0"                     },
-  { "game.panel.element_3_count.class",                "none"                  },
-  { "game.panel.element_3_count.style",                "none"                  },
-  { "game.panel.element_4.x",                  "-1"                    },
-  { "game.panel.element_4.y",                  "-1"                    },
-  { "game.panel.element_4.tile_size",          "16"                    },
-  { "game.panel.element_4.element",            "empty_space"           },
-  { "game.panel.element_4.draw_masked",                "false"                 },
-  { "game.panel.element_4.draw_order",         "0"                     },
-  { "game.panel.element_4.class",              "none"                  },
-  { "game.panel.element_4.style",              "none"                  },
-  { "game.panel.element_4_count.x",            "-1"                    },
-  { "game.panel.element_4_count.y",            "-1"                    },
-  { "game.panel.element_4_count.align",                "left"                  },
-  { "game.panel.element_4_count.valign",       "top"                   },
-  { "game.panel.element_4_count.digits",       "-1"                    },
-  { "game.panel.element_4_count.font",         "font.text_2"           },
-  { "game.panel.element_4_count.element",      "empty_space"           },
-  { "game.panel.element_4_count.draw_masked",  "true"                  },
-  { "game.panel.element_4_count.draw_order",   "0"                     },
-  { "game.panel.element_4_count.class",                "none"                  },
-  { "game.panel.element_4_count.style",                "none"                  },
-  { "game.panel.element_5.x",                  "-1"                    },
-  { "game.panel.element_5.y",                  "-1"                    },
-  { "game.panel.element_5.tile_size",          "16"                    },
-  { "game.panel.element_5.element",            "empty_space"           },
-  { "game.panel.element_5.draw_masked",                "false"                 },
-  { "game.panel.element_5.draw_order",         "0"                     },
-  { "game.panel.element_5.class",              "none"                  },
-  { "game.panel.element_5.style",              "none"                  },
-  { "game.panel.element_5_count.x",            "-1"                    },
-  { "game.panel.element_5_count.y",            "-1"                    },
-  { "game.panel.element_5_count.align",                "left"                  },
-  { "game.panel.element_5_count.valign",       "top"                   },
-  { "game.panel.element_5_count.digits",       "-1"                    },
-  { "game.panel.element_5_count.font",         "font.text_2"           },
-  { "game.panel.element_5_count.element",      "empty_space"           },
-  { "game.panel.element_5_count.draw_masked",  "true"                  },
-  { "game.panel.element_5_count.draw_order",   "0"                     },
-  { "game.panel.element_5_count.class",                "none"                  },
-  { "game.panel.element_5_count.style",                "none"                  },
-  { "game.panel.element_6.x",                  "-1"                    },
-  { "game.panel.element_6.y",                  "-1"                    },
-  { "game.panel.element_6.tile_size",          "16"                    },
-  { "game.panel.element_6.element",            "empty_space"           },
-  { "game.panel.element_6.draw_masked",                "false"                 },
-  { "game.panel.element_6.draw_order",         "0"                     },
-  { "game.panel.element_6.class",              "none"                  },
-  { "game.panel.element_6.style",              "none"                  },
-  { "game.panel.element_6_count.x",            "-1"                    },
-  { "game.panel.element_6_count.y",            "-1"                    },
-  { "game.panel.element_6_count.align",                "left"                  },
-  { "game.panel.element_6_count.valign",       "top"                   },
-  { "game.panel.element_6_count.digits",       "-1"                    },
-  { "game.panel.element_6_count.font",         "font.text_2"           },
-  { "game.panel.element_6_count.element",      "empty_space"           },
-  { "game.panel.element_6_count.draw_masked",  "true"                  },
-  { "game.panel.element_6_count.draw_order",   "0"                     },
-  { "game.panel.element_6_count.class",                "none"                  },
-  { "game.panel.element_6_count.style",                "none"                  },
-  { "game.panel.element_7.x",                  "-1"                    },
-  { "game.panel.element_7.y",                  "-1"                    },
-  { "game.panel.element_7.tile_size",          "16"                    },
-  { "game.panel.element_7.element",            "empty_space"           },
-  { "game.panel.element_7.draw_masked",                "false"                 },
-  { "game.panel.element_7.draw_order",         "0"                     },
-  { "game.panel.element_7.class",              "none"                  },
-  { "game.panel.element_7.style",              "none"                  },
-  { "game.panel.element_7_count.x",            "-1"                    },
-  { "game.panel.element_7_count.y",            "-1"                    },
-  { "game.panel.element_7_count.align",                "left"                  },
-  { "game.panel.element_7_count.valign",       "top"                   },
-  { "game.panel.element_7_count.digits",       "-1"                    },
-  { "game.panel.element_7_count.font",         "font.text_2"           },
-  { "game.panel.element_7_count.element",      "empty_space"           },
-  { "game.panel.element_7_count.draw_masked",  "true"                  },
-  { "game.panel.element_7_count.draw_order",   "0"                     },
-  { "game.panel.element_7_count.class",                "none"                  },
-  { "game.panel.element_7_count.style",                "none"                  },
-  { "game.panel.element_8.x",                  "-1"                    },
-  { "game.panel.element_8.y",                  "-1"                    },
-  { "game.panel.element_8.tile_size",          "16"                    },
-  { "game.panel.element_8.element",            "empty_space"           },
-  { "game.panel.element_8.draw_masked",                "false"                 },
-  { "game.panel.element_8.draw_order",         "0"                     },
-  { "game.panel.element_8.class",              "none"                  },
-  { "game.panel.element_8.style",              "none"                  },
-  { "game.panel.element_8_count.x",            "-1"                    },
-  { "game.panel.element_8_count.y",            "-1"                    },
-  { "game.panel.element_8_count.align",                "left"                  },
-  { "game.panel.element_8_count.valign",       "top"                   },
-  { "game.panel.element_8_count.digits",       "-1"                    },
-  { "game.panel.element_8_count.font",         "font.text_2"           },
-  { "game.panel.element_8_count.element",      "empty_space"           },
-  { "game.panel.element_8_count.draw_masked",  "true"                  },
-  { "game.panel.element_8_count.draw_order",   "0"                     },
-  { "game.panel.element_8_count.class",                "none"                  },
-  { "game.panel.element_8_count.style",                "none"                  },
-
-  { "game.panel.ce_score_1.x",                 "-1"                    },
-  { "game.panel.ce_score_1.y",                 "-1"                    },
-  { "game.panel.ce_score_1.align",             "left"                  },
-  { "game.panel.ce_score_1.valign",            "top"                   },
-  { "game.panel.ce_score_1.digits",            "-1"                    },
-  { "game.panel.ce_score_1.font",              "font.text_2"           },
-  { "game.panel.ce_score_1.element",           "empty_space"           },
-  { "game.panel.ce_score_1.draw_masked",       "true"                  },
-  { "game.panel.ce_score_1.draw_order",                "0"                     },
-  { "game.panel.ce_score_1.class",             "none"                  },
-  { "game.panel.ce_score_1.style",             "none"                  },
-  { "game.panel.ce_score_1_element.x",         "-1"                    },
-  { "game.panel.ce_score_1_element.y",         "-1"                    },
-  { "game.panel.ce_score_1_element.tile_size", "16"                    },
-  { "game.panel.ce_score_1_element.element",   "empty_space"           },
-  { "game.panel.ce_score_1_element.draw_masked","false"                        },
-  { "game.panel.ce_score_1_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_1_element.class",     "none"                  },
-  { "game.panel.ce_score_1_element.style",     "none"                  },
-  { "game.panel.ce_score_2.x",                 "-1"                    },
-  { "game.panel.ce_score_2.y",                 "-1"                    },
-  { "game.panel.ce_score_2.align",             "left"                  },
-  { "game.panel.ce_score_2.valign",            "top"                   },
-  { "game.panel.ce_score_2.digits",            "-1"                    },
-  { "game.panel.ce_score_2.font",              "font.text_2"           },
-  { "game.panel.ce_score_2.element",           "empty_space"           },
-  { "game.panel.ce_score_2.draw_masked",       "true"                  },
-  { "game.panel.ce_score_2.draw_order",                "0"                     },
-  { "game.panel.ce_score_2.class",             "none"                  },
-  { "game.panel.ce_score_2.style",             "none"                  },
-  { "game.panel.ce_score_2_element.x",         "-1"                    },
-  { "game.panel.ce_score_2_element.y",         "-1"                    },
-  { "game.panel.ce_score_2_element.tile_size", "16"                    },
-  { "game.panel.ce_score_2_element.element",   "empty_space"           },
-  { "game.panel.ce_score_2_element.draw_masked","false"                        },
-  { "game.panel.ce_score_2_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_2_element.class",     "none"                  },
-  { "game.panel.ce_score_2_element.style",     "none"                  },
-  { "game.panel.ce_score_3.x",                 "-1"                    },
-  { "game.panel.ce_score_3.y",                 "-1"                    },
-  { "game.panel.ce_score_3.align",             "left"                  },
-  { "game.panel.ce_score_3.valign",            "top"                   },
-  { "game.panel.ce_score_3.digits",            "-1"                    },
-  { "game.panel.ce_score_3.font",              "font.text_2"           },
-  { "game.panel.ce_score_3.element",           "empty_space"           },
-  { "game.panel.ce_score_3.draw_masked",       "true"                  },
-  { "game.panel.ce_score_3.draw_order",                "0"                     },
-  { "game.panel.ce_score_3.class",             "none"                  },
-  { "game.panel.ce_score_3.style",             "none"                  },
-  { "game.panel.ce_score_3_element.x",         "-1"                    },
-  { "game.panel.ce_score_3_element.y",         "-1"                    },
-  { "game.panel.ce_score_3_element.tile_size", "16"                    },
-  { "game.panel.ce_score_3_element.element",   "empty_space"           },
-  { "game.panel.ce_score_3_element.draw_masked","false"                        },
-  { "game.panel.ce_score_3_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_3_element.class",     "none"                  },
-  { "game.panel.ce_score_3_element.style",     "none"                  },
-  { "game.panel.ce_score_4.x",                 "-1"                    },
-  { "game.panel.ce_score_4.y",                 "-1"                    },
-  { "game.panel.ce_score_4.align",             "left"                  },
-  { "game.panel.ce_score_4.valign",            "top"                   },
-  { "game.panel.ce_score_4.digits",            "-1"                    },
-  { "game.panel.ce_score_4.font",              "font.text_2"           },
-  { "game.panel.ce_score_4.element",           "empty_space"           },
-  { "game.panel.ce_score_4.draw_masked",       "true"                  },
-  { "game.panel.ce_score_4.draw_order",                "0"                     },
-  { "game.panel.ce_score_4.class",             "none"                  },
-  { "game.panel.ce_score_4.style",             "none"                  },
-  { "game.panel.ce_score_4_element.x",         "-1"                    },
-  { "game.panel.ce_score_4_element.y",         "-1"                    },
-  { "game.panel.ce_score_4_element.tile_size", "16"                    },
-  { "game.panel.ce_score_4_element.element",   "empty_space"           },
-  { "game.panel.ce_score_4_element.draw_masked","false"                        },
-  { "game.panel.ce_score_4_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_4_element.class",     "none"                  },
-  { "game.panel.ce_score_4_element.style",     "none"                  },
-  { "game.panel.ce_score_5.x",                 "-1"                    },
-  { "game.panel.ce_score_5.y",                 "-1"                    },
-  { "game.panel.ce_score_5.align",             "left"                  },
-  { "game.panel.ce_score_5.valign",            "top"                   },
-  { "game.panel.ce_score_5.digits",            "-1"                    },
-  { "game.panel.ce_score_5.font",              "font.text_2"           },
-  { "game.panel.ce_score_5.element",           "empty_space"           },
-  { "game.panel.ce_score_5.draw_masked",       "true"                  },
-  { "game.panel.ce_score_5.draw_order",                "0"                     },
-  { "game.panel.ce_score_5.class",             "none"                  },
-  { "game.panel.ce_score_5.style",             "none"                  },
-  { "game.panel.ce_score_5_element.x",         "-1"                    },
-  { "game.panel.ce_score_5_element.y",         "-1"                    },
-  { "game.panel.ce_score_5_element.tile_size", "16"                    },
-  { "game.panel.ce_score_5_element.element",   "empty_space"           },
-  { "game.panel.ce_score_5_element.draw_masked","false"                        },
-  { "game.panel.ce_score_5_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_5_element.class",     "none"                  },
-  { "game.panel.ce_score_5_element.style",     "none"                  },
-  { "game.panel.ce_score_6.x",                 "-1"                    },
-  { "game.panel.ce_score_6.y",                 "-1"                    },
-  { "game.panel.ce_score_6.align",             "left"                  },
-  { "game.panel.ce_score_6.valign",            "top"                   },
-  { "game.panel.ce_score_6.digits",            "-1"                    },
-  { "game.panel.ce_score_6.font",              "font.text_2"           },
-  { "game.panel.ce_score_6.element",           "empty_space"           },
-  { "game.panel.ce_score_6.draw_masked",       "true"                  },
-  { "game.panel.ce_score_6.draw_order",                "0"                     },
-  { "game.panel.ce_score_6.class",             "none"                  },
-  { "game.panel.ce_score_6.style",             "none"                  },
-  { "game.panel.ce_score_6_element.x",         "-1"                    },
-  { "game.panel.ce_score_6_element.y",         "-1"                    },
-  { "game.panel.ce_score_6_element.tile_size", "16"                    },
-  { "game.panel.ce_score_6_element.element",   "empty_space"           },
-  { "game.panel.ce_score_6_element.draw_masked","false"                        },
-  { "game.panel.ce_score_6_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_6_element.class",     "none"                  },
-  { "game.panel.ce_score_6_element.style",     "none"                  },
-  { "game.panel.ce_score_7.x",                 "-1"                    },
-  { "game.panel.ce_score_7.y",                 "-1"                    },
-  { "game.panel.ce_score_7.align",             "left"                  },
-  { "game.panel.ce_score_7.valign",            "top"                   },
-  { "game.panel.ce_score_7.digits",            "-1"                    },
-  { "game.panel.ce_score_7.font",              "font.text_2"           },
-  { "game.panel.ce_score_7.element",           "empty_space"           },
-  { "game.panel.ce_score_7.draw_masked",       "true"                  },
-  { "game.panel.ce_score_7.draw_order",                "0"                     },
-  { "game.panel.ce_score_7.class",             "none"                  },
-  { "game.panel.ce_score_7.style",             "none"                  },
-  { "game.panel.ce_score_7_element.x",         "-1"                    },
-  { "game.panel.ce_score_7_element.y",         "-1"                    },
-  { "game.panel.ce_score_7_element.tile_size", "16"                    },
-  { "game.panel.ce_score_7_element.element",   "empty_space"           },
-  { "game.panel.ce_score_7_element.draw_masked","false"                        },
-  { "game.panel.ce_score_7_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_7_element.class",     "none"                  },
-  { "game.panel.ce_score_7_element.style",     "none"                  },
-  { "game.panel.ce_score_8.x",                 "-1"                    },
-  { "game.panel.ce_score_8.y",                 "-1"                    },
-  { "game.panel.ce_score_8.align",             "left"                  },
-  { "game.panel.ce_score_8.valign",            "top"                   },
-  { "game.panel.ce_score_8.digits",            "-1"                    },
-  { "game.panel.ce_score_8.font",              "font.text_2"           },
-  { "game.panel.ce_score_8.element",           "empty_space"           },
-  { "game.panel.ce_score_8.draw_masked",       "true"                  },
-  { "game.panel.ce_score_8.draw_order",                "0"                     },
-  { "game.panel.ce_score_8.class",             "none"                  },
-  { "game.panel.ce_score_8.style",             "none"                  },
-  { "game.panel.ce_score_8_element.x",         "-1"                    },
-  { "game.panel.ce_score_8_element.y",         "-1"                    },
-  { "game.panel.ce_score_8_element.tile_size", "16"                    },
-  { "game.panel.ce_score_8_element.element",   "empty_space"           },
-  { "game.panel.ce_score_8_element.draw_masked","false"                        },
-  { "game.panel.ce_score_8_element.draw_order",        "0"                     },
-  { "game.panel.ce_score_8_element.class",     "none"                  },
-  { "game.panel.ce_score_8_element.style",     "none"                  },
-
-  { "game.panel.player_name.x",                        "-1"                    },
-  { "game.panel.player_name.y",                        "-1"                    },
-  { "game.panel.player_name.align",            "left"                  },
-  { "game.panel.player_name.valign",           "top"                   },
-  { "game.panel.player_name.chars",            "-1"                    },
-  { "game.panel.player_name.font",             "font.text_2"           },
-  { "game.panel.player_name.draw_masked",      "true"                  },
-  { "game.panel.player_name.draw_order",       "0"                     },
-  { "game.panel.player_name.class",            "none"                  },
-  { "game.panel.player_name.style",            "none"                  },
-
-  { "game.panel.level_name.x",                 "-1"                    },
-  { "game.panel.level_name.y",                 "-1"                    },
-  { "game.panel.level_name.align",             "left"                  },
-  { "game.panel.level_name.valign",            "top"                   },
-  { "game.panel.level_name.chars",             "-1"                    },
-  { "game.panel.level_name.font",              "font.text_2"           },
-  { "game.panel.level_name.draw_masked",       "true"                  },
-  { "game.panel.level_name.draw_order",                "0"                     },
-  { "game.panel.level_name.class",             "none"                  },
-  { "game.panel.level_name.style",             "none"                  },
-  { "game.panel.level_author.x",               "-1"                    },
-  { "game.panel.level_author.y",               "-1"                    },
-  { "game.panel.level_author.align",           "left"                  },
-  { "game.panel.level_author.valign",          "top"                   },
-  { "game.panel.level_author.chars",           "-1"                    },
-  { "game.panel.level_author.font",            "font.text_2"           },
-  { "game.panel.level_author.draw_masked",     "true"                  },
-  { "game.panel.level_author.draw_order",      "0"                     },
-  { "game.panel.level_author.class",           "none"                  },
-  { "game.panel.level_author.style",           "none"                  },
-
-  { "game.button.stop.x",                      "5"                     },
-  { "game.button.stop.y",                      "215"                   },
-  { "game.button.pause.x",                     "35"                    },
-  { "game.button.pause.y",                     "215"                   },
-  { "game.button.play.x",                      "65"                    },
-  { "game.button.play.y",                      "215"                   },
-  { "game.button.undo.x",                      "-1"                    },
-  { "game.button.undo.y",                      "-1"                    },
-  { "game.button.redo.x",                      "-1"                    },
-  { "game.button.redo.y",                      "-1"                    },
-  { "game.button.save.x",                      "-1"                    },
-  { "game.button.save.y",                      "-1"                    },
-  { "game.button.pause2.x",                    "-1"                    },
-  { "game.button.pause2.y",                    "-1"                    },
-  { "game.button.load.x",                      "-1"                    },
-  { "game.button.load.y",                      "-1"                    },
-  { "game.button.sound_music.x",               "5"                     },
-  { "game.button.sound_music.y",               "245"                   },
-  { "game.button.sound_loops.x",               "35"                    },
-  { "game.button.sound_loops.y",               "245"                   },
-  { "game.button.sound_simple.x",              "65"                    },
-  { "game.button.sound_simple.y",              "245"                   },
-
-  { "game.button.panel_stop.x",                        "-1"                    },
-  { "game.button.panel_stop.y",                        "-1"                    },
-  { "game.button.panel_pause.x",               "-1"                    },
-  { "game.button.panel_pause.y",               "-1"                    },
-  { "game.button.panel_play.x",                        "-1"                    },
-  { "game.button.panel_play.y",                        "-1"                    },
-  { "game.button.panel_sound_music.x",         "-1"                    },
-  { "game.button.panel_sound_music.y",         "-1"                    },
-  { "game.button.panel_sound_loops.x",         "-1"                    },
-  { "game.button.panel_sound_loops.y",         "-1"                    },
-  { "game.button.panel_sound_simple.x",                "-1"                    },
-  { "game.button.panel_sound_simple.y",                "-1"                    },
-
-  { "game.button.touch_stop.x",                        "0"                     },
-  { "game.button.touch_stop.y",                        "0"                     },
-  { "game.button.touch_pause.x",               "-60"                   },
-  { "game.button.touch_pause.y",               "0"                     },
-
-  { "tape.button.eject.x",                     "5"                     },
-  { "tape.button.eject.y",                     "77"                    },
-  { "tape.button.stop.x",                      "23"                    },
-  { "tape.button.stop.y",                      "77"                    },
-  { "tape.button.pause.x",                     "41"                    },
-  { "tape.button.pause.y",                     "77"                    },
-  { "tape.button.record.x",                    "59"                    },
-  { "tape.button.record.y",                    "77"                    },
-  { "tape.button.play.x",                      "77"                    },
-  { "tape.button.play.y",                      "77"                    },
-
-  { "tape.button.insert_solution.x",           "-1"                    },
-  { "tape.button.insert_solution.y",           "-1"                    },
-  { "tape.button.play_solution.x",             "-1"                    },
-  { "tape.button.play_solution.y",             "-1"                    },
-
-  { "tape.symbol.eject.x",                     "-1"                    },
-  { "tape.symbol.eject.y",                     "-1"                    },
-  { "tape.symbol.stop.x",                      "-1"                    },
-  { "tape.symbol.stop.y",                      "-1"                    },
-  { "tape.symbol.pause.x",                     "40"                    },
-  { "tape.symbol.pause.y",                     "41"                    },
-  { "tape.symbol.record.x",                    "25"                    },
-  { "tape.symbol.record.y",                    "41"                    },
-  { "tape.symbol.play.x",                      "57"                    },
-  { "tape.symbol.play.y",                      "41"                    },
-  { "tape.symbol.fast_forward.x",              "39"                    },
-  { "tape.symbol.fast_forward.y",              "42"                    },
-  { "tape.symbol.warp_forward.x",              "39"                    },
-  { "tape.symbol.warp_forward.y",              "42"                    },
-  { "tape.symbol.warp_forward_blind.x",                "39"                    },
-  { "tape.symbol.warp_forward_blind.y",                "42"                    },
-  { "tape.symbol.pause_before_end.x",          "-1"                    },
-  { "tape.symbol.pause_before_end.y",          "-1"                    },
-  { "tape.symbol.single_step.x",               "-1"                    },
-  { "tape.symbol.single_step.y",               "-1"                    },
-
-  { "tape.label.eject.x",                      "-1"                    },
-  { "tape.label.eject.y",                      "-1"                    },
-  { "tape.label.stop.x",                       "-1"                    },
-  { "tape.label.stop.y",                       "-1"                    },
-  { "tape.label.pause.x",                      "5"                     },
-  { "tape.label.pause.y",                      "61"                    },
-  { "tape.label.record.x",                     "5"                     },
-  { "tape.label.record.y",                     "41"                    },
-  { "tape.label.play.x",                       "70"                    },
-  { "tape.label.play.y",                       "41"                    },
-  { "tape.label.fast_forward.x",               "5"                     },
-  { "tape.label.fast_forward.y",               "42"                    },
-  { "tape.label.warp_forward.x",               "5"                     },
-  { "tape.label.warp_forward.y",               "42"                    },
-  { "tape.label.warp_forward_blind.x",         "5"                     },
-  { "tape.label.warp_forward_blind.y",         "42"                    },
-  { "tape.label.pause_before_end.x",           "5"                     },
-  { "tape.label.pause_before_end.y",           "42"                    },
-  { "tape.label.single_step.x",                        "57"                    },
-  { "tape.label.single_step.y",                        "42"                    },
-
-  { "tape.label.date.x",                       "5"                     },
-  { "tape.label.date.y",                       "5"                     },
-  { "tape.label.time.x",                       "46"                    },
-  { "tape.label.time.y",                       "55"                    },
-
-  { "tape.text.date.x",                                "7"                     },
-  { "tape.text.date.y",                                "19"                    },
-  { "tape.text.date.align",                    "left"                  },
-  { "tape.text.date.valign",                   "top"                   },
-  { "tape.text.date.digits",                   "-1"                    },
-  { "tape.text.date.xoffset",                  "27"                    },
-  { "tape.text.date.2nd_xoffset",              "64"                    },
-  { "tape.text.date.font",                     "font.tape_recorder"    },
-  { "tape.text.date.draw_masked",              "false"                 },
-
-  { "tape.text.date_yyyy.x",                   "-1"                    },
-  { "tape.text.date_yyyy.y",                   "-1"                    },
-  { "tape.text.date_yyyy.align",               "left"                  },
-  { "tape.text.date_yyyy.valign",              "top"                   },
-  { "tape.text.date_yyyy.digits",              "4"                     },
-  { "tape.text.date_yyyy.font",                        "font.tape_recorder"    },
-  { "tape.text.date_yyyy.draw_masked",         "false"                 },
-  { "tape.text.date_yy.x",                     "-1"                    },
-  { "tape.text.date_yy.y",                     "-1"                    },
-  { "tape.text.date_yy.align",                 "left"                  },
-  { "tape.text.date_yy.valign",                        "top"                   },
-  { "tape.text.date_yy.digits",                        "2"                     },
-  { "tape.text.date_yy.font",                  "font.tape_recorder"    },
-  { "tape.text.date_yy.draw_masked",           "false"                 },
-  { "tape.text.date_mon.x",                    "-1"                    },
-  { "tape.text.date_mon.y",                    "-1"                    },
-  { "tape.text.date_mon.align",                        "left"                  },
-  { "tape.text.date_mon.valign",               "top"                   },
-  { "tape.text.date_mon.chars",                        "3"                     },
-  { "tape.text.date_mon.font",                 "font.tape_recorder"    },
-  { "tape.text.date_mon.draw_masked",          "false"                 },
-  { "tape.text.date_mm.x",                     "-1"                    },
-  { "tape.text.date_mm.y",                     "-1"                    },
-  { "tape.text.date_mm.align",                 "left"                  },
-  { "tape.text.date_mm.valign",                        "top"                   },
-  { "tape.text.date_mm.digits",                        "2"                     },
-  { "tape.text.date_mm.font",                  "font.tape_recorder"    },
-  { "tape.text.date_mm.draw_masked",           "false"                 },
-  { "tape.text.date_dd.x",                     "-1"                    },
-  { "tape.text.date_dd.y",                     "-1"                    },
-  { "tape.text.date_dd.align",                 "left"                  },
-  { "tape.text.date_dd.valign",                        "top"                   },
-  { "tape.text.date_dd.digits",                        "2"                     },
-  { "tape.text.date_dd.font",                  "font.tape_recorder"    },
-  { "tape.text.date_dd.draw_masked",           "false"                 },
-
-  { "tape.text.time.x",                                "44"                    },
-  { "tape.text.time.y",                                "55"                    },
-  { "tape.text.time.align",                    "left"                  },
-  { "tape.text.time.valign",                   "top"                   },
-  { "tape.text.time.digits",                   "-1"                    },
-  { "tape.text.time.xoffset",                  "27"                    },
-  { "tape.text.time.font",                     "font.tape_recorder"    },
-  { "tape.text.time.draw_masked",              "false"                 },
-
-  { "tape.text.time_hh.x",                     "-1"                    },
-  { "tape.text.time_hh.y",                     "-1"                    },
-  { "tape.text.time_hh.align",                 "left"                  },
-  { "tape.text.time_hh.valign",                        "top"                   },
-  { "tape.text.time_hh.digits",                        "2"                     },
-  { "tape.text.time_hh.font",                  "font.tape_recorder"    },
-  { "tape.text.time_hh.draw_masked",           "false"                 },
-  { "tape.text.time_mm.x",                     "-1"                    },
-  { "tape.text.time_mm.y",                     "-1"                    },
-  { "tape.text.time_mm.align",                 "left"                  },
-  { "tape.text.time_mm.valign",                        "top"                   },
-  { "tape.text.time_mm.digits",                        "2"                     },
-  { "tape.text.time_mm.font",                  "font.tape_recorder"    },
-  { "tape.text.time_mm.draw_masked",           "false"                 },
-  { "tape.text.time_ss.x",                     "-1"                    },
-  { "tape.text.time_ss.y",                     "-1"                    },
-  { "tape.text.time_ss.align",                 "left"                  },
-  { "tape.text.time_ss.valign",                        "top"                   },
-  { "tape.text.time_ss.digits",                        "2"                     },
-  { "tape.text.time_ss.font",                  "font.tape_recorder"    },
-  { "tape.text.time_ss.draw_masked",           "false"                 },
-
-  { "tape.text.frame.x",                       "-1"                    },
-  { "tape.text.frame.y",                       "-1"                    },
-  { "tape.text.frame.align",                   "left"                  },
-  { "tape.text.frame.valign",                  "top"                   },
-  { "tape.text.frame.digits",                  "-1"                    },
-  { "tape.text.frame.font",                    "font.tape_recorder"    },
-  { "tape.text.frame.draw_masked",             "false"                 },
-
-  { "tape.show_game_buttons",                  "false"                 },
-
-  { "editor.button.prev_level.x",              "5"                     },
-  { "editor.button.prev_level.y",              "5"                     },
-  { "editor.button.next_level.x",              "79"                    },
-  { "editor.button.next_level.y",              "5"                     },
-
-  { "editor.button.properties.x",              "5"                     },
-  { "editor.button.properties.y",              "230"                   },
-
-  { "editor.button.element_left.x",            "-1"                    },
-  { "editor.button.element_left.y",            "-1"                    },
-  { "editor.button.element_left.tile_size",    "-1"                    },
-  { "editor.button.element_middle.x",          "-1"                    },
-  { "editor.button.element_middle.y",          "-1"                    },
-  { "editor.button.element_middle.tile_size",  "-1"                    },
-  { "editor.button.element_right.x",           "-1"                    },
-  { "editor.button.element_right.y",           "-1"                    },
-  { "editor.button.element_right.tile_size",   "-1"                    },
-
-  { "editor.button.palette.x",                 "-1"                    },
-  { "editor.button.palette.y",                 "-1"                    },
-
-  { "editor.button.draw_single.x",             "6"                     },
-  { "editor.button.draw_single.y",             "6"                     },
-  { "editor.button.draw_connected.x",          "28"                    },
-  { "editor.button.draw_connected.y",          "6"                     },
-  { "editor.button.draw_line.x",               "50"                    },
-  { "editor.button.draw_line.y",               "6"                     },
-  { "editor.button.draw_arc.x",                        "72"                    },
-  { "editor.button.draw_arc.y",                        "6"                     },
-  { "editor.button.draw_rectangle.x",          "6"                     },
-  { "editor.button.draw_rectangle.y",          "28"                    },
-  { "editor.button.draw_filled_box.x",         "28"                    },
-  { "editor.button.draw_filled_box.y",         "28"                    },
-  { "editor.button.rotate_up.x",               "50"                    },
-  { "editor.button.rotate_up.y",               "28"                    },
-  { "editor.button.draw_text.x",               "72"                    },
-  { "editor.button.draw_text.y",               "28"                    },
-  { "editor.button.flood_fill.x",              "6"                     },
-  { "editor.button.flood_fill.y",              "50"                    },
-  { "editor.button.rotate_left.x",             "28"                    },
-  { "editor.button.rotate_left.y",             "50"                    },
-  { "editor.button.zoom_level.x",              "50"                    },
-  { "editor.button.zoom_level.y",              "50"                    },
-  { "editor.button.rotate_right.x",            "72"                    },
-  { "editor.button.rotate_right.y",            "50"                    },
-  { "editor.button.draw_random.x",             "6"                     },
-  { "editor.button.draw_random.y",             "72"                    },
-  { "editor.button.grab_brush.x",              "28"                    },
-  { "editor.button.grab_brush.y",              "72"                    },
-  { "editor.button.rotate_down.x",             "50"                    },
-  { "editor.button.rotate_down.y",             "72"                    },
-  { "editor.button.pick_element.x",            "72"                    },
-  { "editor.button.pick_element.y",            "72"                    },
-
-  { "editor.button.ce_copy_from.x",            "28"                    },
-  { "editor.button.ce_copy_from.y",            "6"                     },
-  { "editor.button.ce_copy_to.x",              "50"                    },
-  { "editor.button.ce_copy_to.y",              "6"                     },
-  { "editor.button.ce_swap.x",                 "72"                    },
-  { "editor.button.ce_swap.y",                 "6"                     },
-  { "editor.button.ce_copy.x",                 "6"                     },
-  { "editor.button.ce_copy.y",                 "72"                    },
-  { "editor.button.ce_paste.x",                        "28"                    },
-  { "editor.button.ce_paste.y",                        "72"                    },
-
-  { "editor.button.undo.x",                    "5"                     },
-  { "editor.button.undo.y",                    "99"                    },
-  { "editor.button.conf.x",                    "35"                    },
-  { "editor.button.conf.y",                    "99"                    },
-  { "editor.button.save.x",                    "65"                    },
-  { "editor.button.save.y",                    "99"                    },
-  { "editor.button.clear.x",                   "5"                     },
-  { "editor.button.clear.y",                   "119"                   },
-  { "editor.button.test.x",                    "35"                    },
-  { "editor.button.test.y",                    "119"                   },
-  { "editor.button.exit.x",                    "65"                    },
-  { "editor.button.exit.y",                    "119"                   },
-
-  { "editor.input.level_number.x",             "29"                    },
-  { "editor.input.level_number.y",             "5"                     },
-
-  { "editor.palette.x",                                "5"                     },
-  { "editor.palette.y",                                "30"                    },
-  { "editor.palette.cols",                     "4"                     },
-  { "editor.palette.rows",                     "10"                    },
-  { "editor.palette.tile_size",                        "16"                    },
-  { "editor.palette.show_as_separate_screen",  "false"                 },
-  { "editor.palette.show_on_element_buttons",  "false"                 },
-
-  { "editor.palette.element_left.x",           "6"                     },
-  { "editor.palette.element_left.y",           "258"                   },
-  { "editor.palette.element_left.tile_size",   "16"                    },
-  { "editor.palette.element_middle.x",         "42"                    },
-  { "editor.palette.element_middle.y",         "258"                   },
-  { "editor.palette.element_middle.tile_size", "16"                    },
-  { "editor.palette.element_right.x",          "78"                    },
-  { "editor.palette.element_right.y",          "258"                   },
-  { "editor.palette.element_right.tile_size",  "16"                    },
-
-  { "editor.drawingarea.tile_size",            "16"                    },
-
-  { "editor.settings.headline.x",              "272"                   },
-  { "editor.settings.headline.y",              "16"                    },
-  { "editor.settings.headline.align",          "center"                },
-  { "editor.settings.element_graphic.x",       "24"                    },
-  { "editor.settings.element_graphic.y",       "64"                    },
-  { "editor.settings.element_name.x",          "-1"                    },
-  { "editor.settings.element_name.y",          "-1"                    },
-  { "editor.settings.tabs.x",                  "24"                    },
-  { "editor.settings.tabs.y",                  "64"                    },
-  { "editor.settings.tabs.2nd_yoffset",                "64"                    },
-  { "editor.settings.tabs.draw_xoffset",       "0"                     },
-  { "editor.settings.tabs.draw_yoffset",       "8"                     },
-  { "editor.settings.tooltip.x",               "-1"                    },
-  { "editor.settings.tooltip.y",               "-1"                    },
-
-  { "editor.gadget.normal_spacing",            "4"                     },
-  { "editor.gadget.small_spacing",             "2"                     },
-  { "editor.gadget.tiny_spacing",              "1"                     },
-  { "editor.gadget.line_spacing",              "4"                     },
-  { "editor.gadget.text_spacing",              "4"                     },
-  { "editor.gadget.separator_line.height",     "2"                     },
-
-  { "request.button.yes.x",                    "2"                     },
-  { "request.button.yes.y",                    "250"                   },
-  { "request.button.no.x",                     "52"                    },
-  { "request.button.no.y",                     "250"                   },
-  { "request.button.confirm.x",                        "2"                     },
-  { "request.button.confirm.y",                        "250"                   },
-  { "request.button.player_1.x",               "35"                    },
-  { "request.button.player_1.y",               "185"                   },
-  { "request.button.player_1.draw_player",     "true"                  },
-  { "request.button.player_1.tile_size",       "16"                    },
-  { "request.button.player_2.x",               "65"                    },
-  { "request.button.player_2.y",               "215"                   },
-  { "request.button.player_2.draw_player",     "true"                  },
-  { "request.button.player_2.tile_size",       "16"                    },
-  { "request.button.player_3.x",               "35"                    },
-  { "request.button.player_3.y",               "245"                   },
-  { "request.button.player_3.draw_player",     "true"                  },
-  { "request.button.player_3.tile_size",       "16"                    },
-  { "request.button.player_4.x",               "5"                     },
-  { "request.button.player_4.y",               "215"                   },
-  { "request.button.player_4.draw_player",     "true"                  },
-  { "request.button.player_4.tile_size",       "16"                    },
-
-  { "request.button.touch_yes.x",              "0"                     },
-  { "request.button.touch_yes.y",              "-56"                   },
-  { "request.button.touch_no.x",               "-92"                   },
-  { "request.button.touch_no.y",               "-56"                   },
-  { "request.button.touch_confirm.x",          "0"                     },
-  { "request.button.touch_confirm.y",          "-56"                   },
-
-  { "request.x",                               "-1"                    },
-  { "request.y",                               "-1"                    },
-  { "request.width",                           "120"                   },
-  { "request.height",                          "300"                   },
-  { "request.border_size",                     "10"                    },
-  { "request.line_spacing",                    "2"                     },
-  { "request.step_offset",                     "10"                    },
-  { "request.step_delay",                      "20"                    },
-  { "request.anim_mode",                       "default"               },
-  { "request.align",                           "center"                },
-  { "request.valign",                          "middle"                },
-  { "request.draw_order",                      "0"                     },
-  { "request.autowrap",                                "false"                 },
-  { "request.centered",                                "true"                  },
-  { "request.wrap_single_words",               "true"                  },
-
-  { "global.use_envelope_request",             "false"                 },
-
-  { "game.graphics_engine_version",            "-1"                    },
-  { "game.forced_scroll_delay_value",          "-1"                    },
-  { "game.use_native_emc_graphics_engine",     "false"                 },
-  { "game.use_native_sp_graphics_engine",      "true"                  },
-  { "game.use_masked_pushing",                 "false"                 },
-  { "game.use_masked_elements",                        "false"                 },
-  { "game.tile_size",                          "32"                    },
-
-  { "[player].boring_delay_fixed",             "1000"                  },
-  { "[player].boring_delay_random",            "1000"                  },
-  { "[player].sleeping_delay_fixed",           "2000"                  },
-  { "[player].sleeping_delay_random",          "2000"                  },
-
-  { "viewport.window.width",                   "672"                   },
-  { "viewport.window.height",                  "560"                   },
-  { "viewport.window.min_width",               "-1"                    },
-  { "viewport.window.min_height",              "-1"                    },
-  { "viewport.window.max_width",               "-1"                    },
-  { "viewport.window.max_height",              "-1"                    },
-  { "viewport.window.TITLE.width",             ARG_DEFAULT             },
-  { "viewport.window.TITLE.height",            ARG_DEFAULT             },
-
-  { "viewport.playfield.x",                    "6"                     },
-  { "viewport.playfield.y",                    "6"                     },
-  { "viewport.playfield.width",                        "548"                   },
-  { "viewport.playfield.height",               "548"                   },
-  { "viewport.playfield.min_width",            "-1"                    },
-  { "viewport.playfield.min_height",           "-1"                    },
-  { "viewport.playfield.max_width",            "-1"                    },
-  { "viewport.playfield.max_height",           "-1"                    },
-  { "viewport.playfield.margin_left",          "0"                     },
-  { "viewport.playfield.margin_right",         "0"                     },
-  { "viewport.playfield.margin_top",           "0"                     },
-  { "viewport.playfield.margin_bottom",                "0"                     },
-  { "viewport.playfield.border_left",          "-1"                    },
-  { "viewport.playfield.border_right",         "-1"                    },
-  { "viewport.playfield.border_top",           "-1"                    },
-  { "viewport.playfield.border_bottom",                "-1"                    },
-  { "viewport.playfield.border_size",          "2"                     },
-  { "viewport.playfield.align_size",           "16"                    },
-  { "viewport.playfield.align",                        "left"                  },
-  { "viewport.playfield.valign",               "top"                   },
-  { "viewport.playfield.MAIN.x",               ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.y",               ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.width",           ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.height",          ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.min_width",       ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.min_height",      ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.max_width",       ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.max_height",      ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.margin_left",     ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.margin_right",    ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.margin_top",      ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.margin_bottom",   ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.border_left",     ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.border_right",    ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.border_top",      ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.border_bottom",   ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.border_size",     ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.align_size",      ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.align",           ARG_DEFAULT             },
-  { "viewport.playfield.MAIN.valign",          ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.x",             ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.y",             ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.width",         ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.height",                ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.min_width",     ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.min_height",    ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.max_width",     ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.max_height",    ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.margin_left",   ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.margin_right",  ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.margin_top",    ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.margin_bottom", ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.border_left",   ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.border_right",  ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.border_top",    ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.border_bottom", ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.border_size",   ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.align_size",    ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.align",         ARG_DEFAULT             },
-  { "viewport.playfield.SCORES.valign",                ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.x",             ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.y",             ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.width",         ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.height",                ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.min_width",     ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.min_height",    ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.max_width",     ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.max_height",    ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.margin_left",   ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.margin_right",  ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.margin_top",    ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.margin_bottom", ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.border_left",   ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.border_right",  ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.border_top",    ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.border_bottom", ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.border_size",   ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.align_size",    ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.align",         ARG_DEFAULT             },
-  { "viewport.playfield.EDITOR.valign",                ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.x",            ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.y",            ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.width",                ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.height",       ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.min_width",    ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.min_height",   ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.max_width",    ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.max_height",   ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.margin_left",  ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.margin_right", ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.margin_top",   ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.margin_bottom",        ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.border_left",  ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.border_right", ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.border_top",   ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.border_bottom",        ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.border_size",  ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.align_size",   ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.align",                ARG_DEFAULT             },
-  { "viewport.playfield.PLAYING.valign",       ARG_DEFAULT             },
-
-  { "viewport.door_1.x",                       "566"                   },
-  { "viewport.door_1.y",                       "60"                    },
-  { "viewport.door_1.width",                   "100"                   },
-  { "viewport.door_1.height",                  "280"                   },
-  { "viewport.door_1.border_size",             "4"                     },
-  { "viewport.door_1.align",                   "left"                  },
-  { "viewport.door_1.valign",                  "top"                   },
-  { "viewport.door_1.MAIN.x",                  ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.y",                  ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.width",              ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.height",             ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.border_size",                ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.align",              ARG_DEFAULT             },
-  { "viewport.door_1.MAIN.valign",             ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.x",                        ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.y",                        ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.width",            ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.height",           ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.border_size",      ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.align",            ARG_DEFAULT             },
-  { "viewport.door_1.SCORES.valign",           ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.x",                        ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.y",                        ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.width",            ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.height",           ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.border_size",      ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.align",            ARG_DEFAULT             },
-  { "viewport.door_1.EDITOR.valign",           ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.x",               ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.y",               ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.width",           ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.height",          ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.border_size",     ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.align",           ARG_DEFAULT             },
-  { "viewport.door_1.PLAYING.valign",          ARG_DEFAULT             },
-
-  { "viewport.door_2.x",                       "566"                   },
-  { "viewport.door_2.y",                       "400"                   },
-  { "viewport.door_2.width",                   "100"                   },
-  { "viewport.door_2.height",                  "100"                   },
-  { "viewport.door_2.border_size",             "4"                     },
-  { "viewport.door_2.align",                   "left"                  },
-  { "viewport.door_2.valign",                  "top"                   },
-  { "viewport.door_2.MAIN.x",                  ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.y",                  ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.width",              ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.height",             ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.border_size",                ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.align",              ARG_DEFAULT             },
-  { "viewport.door_2.MAIN.valign",             ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.x",                        ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.y",                        ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.width",            ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.height",           ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.border_size",      ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.align",            ARG_DEFAULT             },
-  { "viewport.door_2.SCORES.valign",           ARG_DEFAULT             },
-  { "viewport.door_2.EDITOR.x",                        "566"                   },
-  { "viewport.door_2.EDITOR.y",                        "356"                   },
-  { "viewport.door_2.EDITOR.width",            "100"                   },
-  { "viewport.door_2.EDITOR.height",           "144"                   },
-  { "viewport.door_2.EDITOR.border_size",      "4"                     },
-  { "viewport.door_2.EDITOR.align",            "left"                  },
-  { "viewport.door_2.EDITOR.valign",           "top"                   },
-  { "viewport.door_2.PLAYING.x",               ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.y",               ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.width",           ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.height",          ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.border_size",     ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.align",           ARG_DEFAULT             },
-  { "viewport.door_2.PLAYING.valign",          ARG_DEFAULT             },
-
-  { NULL,                                      NULL                    }
+  { "[title_initial].fade_mode",                       "fade"                          },
+  { "[title_initial].fade_delay",                      "500"                           },
+  { "[title_initial].post_delay",                      "250"                           },
+  { "[title_initial].auto_delay",                      "-1"                            },
+  { "[title_initial].auto_delay_unit",                 "ms"                            },
+  { "[title].fade_mode",                               "fade"                          },
+  { "[title].fade_delay",                              "500"                           },
+  { "[title].post_delay",                              "250"                           },
+  { "[title].auto_delay",                              "-1"                            },
+  { "[title].auto_delay_unit",                         "ms"                            },
+
+  { "[titlescreen_initial].sort_priority",             "0"                             },
+  { "[titlescreen_initial].fade_mode",                 ARG_DEFAULT                     },
+  { "[titlescreen_initial].fade_delay",                        ARG_DEFAULT                     },
+  { "[titlescreen_initial].post_delay",                        ARG_DEFAULT                     },
+  { "[titlescreen_initial].auto_delay",                        ARG_DEFAULT                     },
+  { "[titlescreen_initial].auto_delay_unit",           ARG_DEFAULT                     },
+  { "[titlescreen].sort_priority",                     "0"                             },
+  { "[titlescreen].fade_mode",                         ARG_DEFAULT                     },
+  { "[titlescreen].fade_delay",                                ARG_DEFAULT                     },
+  { "[titlescreen].post_delay",                                ARG_DEFAULT                     },
+  { "[titlescreen].auto_delay",                                ARG_DEFAULT                     },
+  { "[titlescreen].auto_delay_unit",                   ARG_DEFAULT                     },
+
+  { "titlescreen_initial_1.sort_priority",             ARG_DEFAULT                     },
+  { "titlescreen_initial_1.fade_mode",                 ARG_DEFAULT                     },
+  { "titlescreen_initial_1.fade_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_1.post_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_1.auto_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_1.auto_delay_unit",           ARG_DEFAULT                     },
+  { "titlescreen_initial_2.sort_priority",             ARG_DEFAULT                     },
+  { "titlescreen_initial_2.fade_mode",                 ARG_DEFAULT                     },
+  { "titlescreen_initial_2.fade_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_2.post_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_2.auto_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_2.auto_delay_unit",           ARG_DEFAULT                     },
+  { "titlescreen_initial_3.sort_priority",             ARG_DEFAULT                     },
+  { "titlescreen_initial_3.fade_mode",                 ARG_DEFAULT                     },
+  { "titlescreen_initial_3.fade_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_3.post_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_3.auto_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_3.auto_delay_unit",           ARG_DEFAULT                     },
+  { "titlescreen_initial_4.sort_priority",             ARG_DEFAULT                     },
+  { "titlescreen_initial_4.fade_mode",                 ARG_DEFAULT                     },
+  { "titlescreen_initial_4.fade_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_4.post_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_4.auto_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_4.auto_delay_unit",           ARG_DEFAULT                     },
+  { "titlescreen_initial_5.sort_priority",             ARG_DEFAULT                     },
+  { "titlescreen_initial_5.fade_mode",                 ARG_DEFAULT                     },
+  { "titlescreen_initial_5.fade_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_5.post_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_5.auto_delay",                        ARG_DEFAULT                     },
+  { "titlescreen_initial_5.auto_delay_unit",           ARG_DEFAULT                     },
+  { "titlescreen_1.sort_priority",                     ARG_DEFAULT                     },
+  { "titlescreen_1.fade_mode",                         ARG_DEFAULT                     },
+  { "titlescreen_1.fade_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_1.post_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_1.auto_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_1.auto_delay_unit",                   ARG_DEFAULT                     },
+  { "titlescreen_2.sort_priority",                     ARG_DEFAULT                     },
+  { "titlescreen_2.fade_mode",                         ARG_DEFAULT                     },
+  { "titlescreen_2.fade_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_2.post_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_2.auto_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_2.auto_delay_unit",                   ARG_DEFAULT                     },
+  { "titlescreen_3.sort_priority",                     ARG_DEFAULT                     },
+  { "titlescreen_3.fade_mode",                         ARG_DEFAULT                     },
+  { "titlescreen_3.fade_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_3.post_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_3.auto_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_3.auto_delay_unit",                   ARG_DEFAULT                     },
+  { "titlescreen_4.sort_priority",                     ARG_DEFAULT                     },
+  { "titlescreen_4.fade_mode",                         ARG_DEFAULT                     },
+  { "titlescreen_4.fade_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_4.post_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_4.auto_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_4.auto_delay_unit",                   ARG_DEFAULT                     },
+  { "titlescreen_5.sort_priority",                     ARG_DEFAULT                     },
+  { "titlescreen_5.fade_mode",                         ARG_DEFAULT                     },
+  { "titlescreen_5.fade_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_5.post_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_5.auto_delay",                                ARG_DEFAULT                     },
+  { "titlescreen_5.auto_delay_unit",                   ARG_DEFAULT                     },
+
+  { "[titlemessage_initial].x",                                "-1"                            },
+  { "[titlemessage_initial].y",                                "-1"                            },
+  { "[titlemessage_initial].width",                    "-1"                            },
+  { "[titlemessage_initial].height",                   "-1"                            },
+  { "[titlemessage_initial].chars",                    "-1"                            },
+  { "[titlemessage_initial].lines",                    "-1"                            },
+  { "[titlemessage_initial].align",                    "center"                        },
+  { "[titlemessage_initial].valign",                   "middle"                        },
+  { "[titlemessage_initial].font",                     "font.text_1"                   },
+  { "[titlemessage_initial].autowrap",                 "false"                         },
+  { "[titlemessage_initial].centered",                 "false"                         },
+  { "[titlemessage_initial].parse_comments",           "false"                         },
+  { "[titlemessage_initial].sort_priority",            "0"                             },
+  { "[titlemessage_initial].fade_mode",                        ARG_DEFAULT                     },
+  { "[titlemessage_initial].fade_delay",               ARG_DEFAULT                     },
+  { "[titlemessage_initial].post_delay",               ARG_DEFAULT                     },
+  { "[titlemessage_initial].auto_delay",               ARG_DEFAULT                     },
+  { "[titlemessage_initial].auto_delay_unit",          ARG_DEFAULT                     },
+  { "[titlemessage].x",                                        "-1"                            },
+  { "[titlemessage].y",                                        "-1"                            },
+  { "[titlemessage].width",                            "-1"                            },
+  { "[titlemessage].height",                           "-1"                            },
+  { "[titlemessage].chars",                            "-1"                            },
+  { "[titlemessage].lines",                            "-1"                            },
+  { "[titlemessage].align",                            "center"                        },
+  { "[titlemessage].valign",                           "middle"                        },
+  { "[titlemessage].font",                             "font.text_1"                   },
+  { "[titlemessage].autowrap",                         "false"                         },
+  { "[titlemessage].centered",                         "false"                         },
+  { "[titlemessage].parse_comments",                   "false"                         },
+  { "[titlemessage].sort_priority",                    "0"                             },
+  { "[titlemessage].fade_mode",                                ARG_DEFAULT                     },
+  { "[titlemessage].fade_delay",                       ARG_DEFAULT                     },
+  { "[titlemessage].post_delay",                       ARG_DEFAULT                     },
+  { "[titlemessage].auto_delay",                       ARG_DEFAULT                     },
+  { "[titlemessage].auto_delay_unit",                  ARG_DEFAULT                     },
+
+  { "titlemessage_initial_1.x",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_1.y",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_1.width",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_1.height",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_1.chars",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_1.lines",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_1.align",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_1.valign",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_1.font",                     ARG_DEFAULT                     },
+  { "titlemessage_initial_1.autowrap",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_1.centered",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_1.parse_comments",           ARG_DEFAULT                     },
+  { "titlemessage_initial_1.sort_priority",            ARG_DEFAULT                     },
+  { "titlemessage_initial_1.fade_mode",                        ARG_DEFAULT                     },
+  { "titlemessage_initial_1.fade_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_1.post_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_1.auto_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_1.auto_delay_unit",          ARG_DEFAULT                     },
+  { "titlemessage_initial_2.x",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_2.y",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_2.width",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_2.height",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_2.chars",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_2.lines",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_2.align",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_2.valign",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_2.font",                     ARG_DEFAULT                     },
+  { "titlemessage_initial_2.autowrap",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_2.centered",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_2.parse_comments",           ARG_DEFAULT                     },
+  { "titlemessage_initial_2.sort_priority",            ARG_DEFAULT                     },
+  { "titlemessage_initial_2.fade_mode",                        ARG_DEFAULT                     },
+  { "titlemessage_initial_2.fade_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_2.post_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_2.auto_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_2.auto_delay_unit",          ARG_DEFAULT                     },
+  { "titlemessage_initial_3.x",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_3.y",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_3.width",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_3.height",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_3.chars",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_3.lines",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_3.align",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_3.valign",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_3.font",                     ARG_DEFAULT                     },
+  { "titlemessage_initial_3.autowrap",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_3.centered",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_3.parse_comments",           ARG_DEFAULT                     },
+  { "titlemessage_initial_3.sort_priority",            ARG_DEFAULT                     },
+  { "titlemessage_initial_3.fade_mode",                        ARG_DEFAULT                     },
+  { "titlemessage_initial_3.fade_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_3.post_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_3.auto_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_3.auto_delay_unit",          ARG_DEFAULT                     },
+  { "titlemessage_initial_4.x",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_4.y",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_4.width",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_4.height",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_4.chars",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_4.lines",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_4.align",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_4.valign",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_4.font",                     ARG_DEFAULT                     },
+  { "titlemessage_initial_4.autowrap",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_4.centered",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_4.parse_comments",           ARG_DEFAULT                     },
+  { "titlemessage_initial_4.sort_priority",            ARG_DEFAULT                     },
+  { "titlemessage_initial_4.fade_mode",                        ARG_DEFAULT                     },
+  { "titlemessage_initial_4.fade_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_4.post_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_4.auto_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_4.auto_delay_unit",          ARG_DEFAULT                     },
+  { "titlemessage_initial_5.x",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_5.y",                                ARG_DEFAULT                     },
+  { "titlemessage_initial_5.width",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_5.height",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_5.chars",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_5.lines",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_5.align",                    ARG_DEFAULT                     },
+  { "titlemessage_initial_5.valign",                   ARG_DEFAULT                     },
+  { "titlemessage_initial_5.font",                     ARG_DEFAULT                     },
+  { "titlemessage_initial_5.autowrap",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_5.centered",                 ARG_DEFAULT                     },
+  { "titlemessage_initial_5.parse_comments",           ARG_DEFAULT                     },
+  { "titlemessage_initial_5.sort_priority",            ARG_DEFAULT                     },
+  { "titlemessage_initial_5.fade_mode",                        ARG_DEFAULT                     },
+  { "titlemessage_initial_5.fade_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_5.post_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_5.auto_delay",               ARG_DEFAULT                     },
+  { "titlemessage_initial_5.auto_delay_unit",          ARG_DEFAULT                     },
+  { "titlemessage_1.x",                                        ARG_DEFAULT                     },
+  { "titlemessage_1.y",                                        ARG_DEFAULT                     },
+  { "titlemessage_1.width",                            ARG_DEFAULT                     },
+  { "titlemessage_1.height",                           ARG_DEFAULT                     },
+  { "titlemessage_1.chars",                            ARG_DEFAULT                     },
+  { "titlemessage_1.lines",                            ARG_DEFAULT                     },
+  { "titlemessage_1.align",                            ARG_DEFAULT                     },
+  { "titlemessage_1.valign",                           ARG_DEFAULT                     },
+  { "titlemessage_1.font",                             ARG_DEFAULT                     },
+  { "titlemessage_1.autowrap",                         ARG_DEFAULT                     },
+  { "titlemessage_1.centered",                         ARG_DEFAULT                     },
+  { "titlemessage_1.parse_comments",                   ARG_DEFAULT                     },
+  { "titlemessage_1.sort_priority",                    ARG_DEFAULT                     },
+  { "titlemessage_1.fade_mode",                                ARG_DEFAULT                     },
+  { "titlemessage_1.fade_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_1.post_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_1.auto_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_1.auto_delay_unit",                  ARG_DEFAULT                     },
+  { "titlemessage_2.x",                                        ARG_DEFAULT                     },
+  { "titlemessage_2.y",                                        ARG_DEFAULT                     },
+  { "titlemessage_2.width",                            ARG_DEFAULT                     },
+  { "titlemessage_2.height",                           ARG_DEFAULT                     },
+  { "titlemessage_2.chars",                            ARG_DEFAULT                     },
+  { "titlemessage_2.lines",                            ARG_DEFAULT                     },
+  { "titlemessage_2.align",                            ARG_DEFAULT                     },
+  { "titlemessage_2.valign",                           ARG_DEFAULT                     },
+  { "titlemessage_2.font",                             ARG_DEFAULT                     },
+  { "titlemessage_2.autowrap",                         ARG_DEFAULT                     },
+  { "titlemessage_2.centered",                         ARG_DEFAULT                     },
+  { "titlemessage_2.parse_comments",                   ARG_DEFAULT                     },
+  { "titlemessage_2.sort_priority",                    ARG_DEFAULT                     },
+  { "titlemessage_2.fade_mode",                                ARG_DEFAULT                     },
+  { "titlemessage_2.fade_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_2.post_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_2.auto_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_2.auto_delay_unit",                  ARG_DEFAULT                     },
+  { "titlemessage_3.x",                                        ARG_DEFAULT                     },
+  { "titlemessage_3.y",                                        ARG_DEFAULT                     },
+  { "titlemessage_3.width",                            ARG_DEFAULT                     },
+  { "titlemessage_3.height",                           ARG_DEFAULT                     },
+  { "titlemessage_3.chars",                            ARG_DEFAULT                     },
+  { "titlemessage_3.lines",                            ARG_DEFAULT                     },
+  { "titlemessage_3.align",                            ARG_DEFAULT                     },
+  { "titlemessage_3.valign",                           ARG_DEFAULT                     },
+  { "titlemessage_3.font",                             ARG_DEFAULT                     },
+  { "titlemessage_3.autowrap",                         ARG_DEFAULT                     },
+  { "titlemessage_3.centered",                         ARG_DEFAULT                     },
+  { "titlemessage_3.parse_comments",                   ARG_DEFAULT                     },
+  { "titlemessage_3.sort_priority",                    ARG_DEFAULT                     },
+  { "titlemessage_3.fade_mode",                                ARG_DEFAULT                     },
+  { "titlemessage_3.fade_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_3.post_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_3.auto_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_3.auto_delay_unit",                  ARG_DEFAULT                     },
+  { "titlemessage_4.x",                                        ARG_DEFAULT                     },
+  { "titlemessage_4.y",                                        ARG_DEFAULT                     },
+  { "titlemessage_4.width",                            ARG_DEFAULT                     },
+  { "titlemessage_4.height",                           ARG_DEFAULT                     },
+  { "titlemessage_4.chars",                            ARG_DEFAULT                     },
+  { "titlemessage_4.lines",                            ARG_DEFAULT                     },
+  { "titlemessage_4.align",                            ARG_DEFAULT                     },
+  { "titlemessage_4.valign",                           ARG_DEFAULT                     },
+  { "titlemessage_4.font",                             ARG_DEFAULT                     },
+  { "titlemessage_4.autowrap",                         ARG_DEFAULT                     },
+  { "titlemessage_4.centered",                         ARG_DEFAULT                     },
+  { "titlemessage_4.parse_comments",                   ARG_DEFAULT                     },
+  { "titlemessage_4.sort_priority",                    ARG_DEFAULT                     },
+  { "titlemessage_4.fade_mode",                                ARG_DEFAULT                     },
+  { "titlemessage_4.fade_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_4.post_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_4.auto_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_4.auto_delay_unit",                  ARG_DEFAULT                     },
+  { "titlemessage_5.x",                                        ARG_DEFAULT                     },
+  { "titlemessage_5.y",                                        ARG_DEFAULT                     },
+  { "titlemessage_5.width",                            ARG_DEFAULT                     },
+  { "titlemessage_5.height",                           ARG_DEFAULT                     },
+  { "titlemessage_5.chars",                            ARG_DEFAULT                     },
+  { "titlemessage_5.lines",                            ARG_DEFAULT                     },
+  { "titlemessage_5.align",                            ARG_DEFAULT                     },
+  { "titlemessage_5.valign",                           ARG_DEFAULT                     },
+  { "titlemessage_5.font",                             ARG_DEFAULT                     },
+  { "titlemessage_5.autowrap",                         ARG_DEFAULT                     },
+  { "titlemessage_5.centered",                         ARG_DEFAULT                     },
+  { "titlemessage_5.parse_comments",                   ARG_DEFAULT                     },
+  { "titlemessage_5.sort_priority",                    ARG_DEFAULT                     },
+  { "titlemessage_5.fade_mode",                                ARG_DEFAULT                     },
+  { "titlemessage_5.fade_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_5.post_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_5.auto_delay",                       ARG_DEFAULT                     },
+  { "titlemessage_5.auto_delay_unit",                  ARG_DEFAULT                     },
+
+  { "readme.x",                                                "-1"                            },
+  { "readme.y",                                                "-1"                            },
+  { "readme.width",                                    "-1"                            },
+  { "readme.height",                                   "-1"                            },
+  { "readme.chars",                                    "-1"                            },
+  { "readme.lines",                                    "-1"                            },
+  { "readme.align",                                    "center"                        },
+  { "readme.valign",                                   "top"                           },
+  { "readme.font",                                     "font.info.levelset"            },
+  { "readme.autowrap",                                 "true"                          },
+  { "readme.centered",                                 "false"                         },
+  { "readme.parse_comments",                           "true"                          },
+  { "readme.sort_priority",                            "0"                             },
+
+  { "global.num_toons",                                        "20"                            },
+
+  { "border.draw_masked.TITLE",                                "false"                         },
+  { "border.draw_masked.MAIN",                         "false"                         },
+  { "border.draw_masked.NAMES",                                "false"                         },
+  { "border.draw_masked.LEVELS",                       "false"                         },
+  { "border.draw_masked.LEVELNR",                      "false"                         },
+  { "border.draw_masked.SCORES",                       "false"                         },
+  { "border.draw_masked.SCOREINFO",                    "false"                         },
+  { "border.draw_masked.EDITOR",                       "false"                         },
+  { "border.draw_masked.INFO",                         "false"                         },
+  { "border.draw_masked.SETUP",                                "false"                         },
+  { "border.draw_masked.PLAYING",                      "false"                         },
+  { "border.draw_masked.DOOR",                         "false"                         },
+
+  { "border.draw_masked_when_fading",                  "true"                          },
+
+  { "init.busy_initial.x",                             "-1"                            },
+  { "init.busy_initial.y",                             "-1"                            },
+  { "init.busy_initial.align",                         "center"                        },
+  { "init.busy_initial.valign",                                "middle"                        },
+  { "init.busy.x",                                     "-1"                            },
+  { "init.busy.y",                                     "-1"                            },
+  { "init.busy.align",                                 "center"                        },
+  { "init.busy.valign",                                        "middle"                        },
+  { "init.busy_playfield.x",                           "-1"                            },
+  { "init.busy_playfield.y",                           "-1"                            },
+  { "init.busy_playfield.align",                       "center"                        },
+  { "init.busy_playfield.valign",                      "middle"                        },
+
+  { "menu.enter_menu.fade_mode",                       "none"                          },
+  { "menu.enter_menu.fade_delay",                      "250"                           },
+  { "menu.enter_menu.post_delay",                      "125"                           },
+  { "menu.leave_menu.fade_mode",                       "none"                          },
+  { "menu.leave_menu.fade_delay",                      "250"                           },
+  { "menu.leave_menu.post_delay",                      "125"                           },
+  { "menu.enter_screen.fade_mode",                     "fade"                          },
+  { "menu.enter_screen.fade_delay",                    "250"                           },
+  { "menu.enter_screen.post_delay",                    "125"                           },
+  { "menu.leave_screen.fade_mode",                     "fade"                          },
+  { "menu.leave_screen.fade_delay",                    "250"                           },
+  { "menu.leave_screen.post_delay",                    "125"                           },
+  { "menu.next_screen.fade_mode",                      "crossfade"                     },
+  { "menu.next_screen.fade_delay",                     "250"                           },
+  { "menu.next_screen.post_delay",                     "125"                           },
+  { "menu.enter_screen.TITLE.fade_mode",               "fade"                          },
+  { "menu.enter_screen.TITLE.fade_delay",              "500"                           },
+  { "menu.enter_screen.TITLE.post_delay",              "250"                           },
+  { "menu.enter_screen.TITLE.auto_delay",              "-1"                            },
+  { "menu.enter_screen.TITLE.auto_delay_unit",         "-1"                            },
+  { "menu.enter_screen.SCORES.fade_mode",              ARG_DEFAULT                     },
+  { "menu.enter_screen.SCORES.fade_delay",             ARG_DEFAULT                     },
+  { "menu.enter_screen.SCORES.post_delay",             ARG_DEFAULT                     },
+  { "menu.enter_screen.SCOREINFO.fade_mode",           ARG_DEFAULT                     },
+  { "menu.enter_screen.SCOREINFO.fade_delay",          ARG_DEFAULT                     },
+  { "menu.enter_screen.SCOREINFO.post_delay",          ARG_DEFAULT                     },
+  { "menu.enter_screen.EDITOR.fade_mode",              ARG_DEFAULT                     },
+  { "menu.enter_screen.EDITOR.fade_delay",             ARG_DEFAULT                     },
+  { "menu.enter_screen.EDITOR.post_delay",             ARG_DEFAULT                     },
+  { "menu.enter_screen.INFO.fade_mode",                        ARG_DEFAULT                     },
+  { "menu.enter_screen.INFO.fade_delay",               ARG_DEFAULT                     },
+  { "menu.enter_screen.INFO.post_delay",               ARG_DEFAULT                     },
+  { "menu.enter_screen.PLAYING.fade_mode",             ARG_DEFAULT                     },
+  { "menu.enter_screen.PLAYING.fade_delay",            ARG_DEFAULT                     },
+  { "menu.enter_screen.PLAYING.post_delay",            ARG_DEFAULT                     },
+  { "menu.leave_screen.TITLE.fade_mode",               "fade"                          },
+  { "menu.leave_screen.TITLE.fade_delay",              "500"                           },
+  { "menu.leave_screen.TITLE.post_delay",              "250"                           },
+  { "menu.leave_screen.TITLE.auto_delay",              "-1"                            },
+  { "menu.leave_screen.TITLE.auto_delay_unit",         "-1"                            },
+  { "menu.leave_screen.SCORES.fade_mode",              ARG_DEFAULT                     },
+  { "menu.leave_screen.SCORES.fade_delay",             ARG_DEFAULT                     },
+  { "menu.leave_screen.SCORES.post_delay",             ARG_DEFAULT                     },
+  { "menu.leave_screen.SCOREINFO.fade_mode",           ARG_DEFAULT                     },
+  { "menu.leave_screen.SCOREINFO.fade_delay",          ARG_DEFAULT                     },
+  { "menu.leave_screen.SCOREINFO.post_delay",          ARG_DEFAULT                     },
+  { "menu.leave_screen.EDITOR.fade_mode",              ARG_DEFAULT                     },
+  { "menu.leave_screen.EDITOR.fade_delay",             ARG_DEFAULT                     },
+  { "menu.leave_screen.EDITOR.post_delay",             ARG_DEFAULT                     },
+  { "menu.leave_screen.INFO.fade_mode",                        ARG_DEFAULT                     },
+  { "menu.leave_screen.INFO.fade_delay",               ARG_DEFAULT                     },
+  { "menu.leave_screen.INFO.post_delay",               ARG_DEFAULT                     },
+  { "menu.leave_screen.PLAYING.fade_mode",             ARG_DEFAULT                     },
+  { "menu.leave_screen.PLAYING.fade_delay",            ARG_DEFAULT                     },
+  { "menu.leave_screen.PLAYING.post_delay",            ARG_DEFAULT                     },
+  { "menu.next_screen.TITLE.fade_mode",                        "fade"                          },
+  { "menu.next_screen.TITLE.fade_delay",               "500"                           },
+  { "menu.next_screen.TITLE.post_delay",               "250"                           },
+  { "menu.next_screen.TITLE.auto_delay",               "-1"                            },
+  { "menu.next_screen.TITLE.auto_delay_unit",          "-1"                            },
+  { "menu.next_screen.INFO.fade_mode",                 ARG_DEFAULT                     },
+  { "menu.next_screen.INFO.fade_delay",                        ARG_DEFAULT                     },
+  { "menu.next_screen.INFO.post_delay",                        ARG_DEFAULT                     },
+
+  { "menu.draw_xoffset",                               "0"                             },
+  { "menu.draw_yoffset",                               "0"                             },
+  { "menu.draw_xoffset.MAIN",                          "0"                             },
+  { "menu.draw_yoffset.MAIN",                          "0"                             },
+  { "menu.draw_xoffset.NAMES",                         "0"                             },
+  { "menu.draw_yoffset.NAMES",                         "0"                             },
+  { "menu.draw_xoffset.LEVELS",                                "0"                             },
+  { "menu.draw_yoffset.LEVELS",                                "0"                             },
+  { "menu.draw_xoffset.LEVELNR",                       "0"                             },
+  { "menu.draw_yoffset.LEVELNR",                       "0"                             },
+  { "menu.draw_xoffset.SCORES",                                "0"                             },
+  { "menu.draw_yoffset.SCORES",                                "0"                             },
+  { "menu.draw_xoffset.SCOREINFO",                     "0"                             },
+  { "menu.draw_yoffset.SCOREINFO",                     "0"                             },
+  { "menu.draw_xoffset.EDITOR",                                "0"                             },
+  { "menu.draw_yoffset.EDITOR",                                "0"                             },
+  { "menu.draw_xoffset.INFO",                          "0"                             },
+  { "menu.draw_yoffset.INFO",                          "0"                             },
+  { "menu.draw_xoffset.INFO[TITLE]",                   "0"                             },
+  { "menu.draw_yoffset.INFO[TITLE]",                   "0"                             },
+  { "menu.draw_xoffset.INFO[ELEMENTS]",                        "0"                             },
+  { "menu.draw_yoffset.INFO[ELEMENTS]",                        "0"                             },
+  { "menu.draw_xoffset.INFO[MUSIC]",                   "0"                             },
+  { "menu.draw_yoffset.INFO[MUSIC]",                   "0"                             },
+  { "menu.draw_xoffset.INFO[CREDITS]",                 "0"                             },
+  { "menu.draw_yoffset.INFO[CREDITS]",                 "0"                             },
+  { "menu.draw_xoffset.INFO[PROGRAM]",                 "0"                             },
+  { "menu.draw_yoffset.INFO[PROGRAM]",                 "0"                             },
+  { "menu.draw_xoffset.INFO[VERSION]",                 "0"                             },
+  { "menu.draw_yoffset.INFO[VERSION]",                 "0"                             },
+  { "menu.draw_xoffset.INFO[LEVELSET]",                        "0"                             },
+  { "menu.draw_yoffset.INFO[LEVELSET]",                        "0"                             },
+  { "menu.draw_xoffset.SETUP",                         "0"                             },
+  { "menu.draw_yoffset.SETUP",                         "0"                             },
+  { "menu.draw_xoffset.SETUP[GAME]",                   "0"                             },
+  { "menu.draw_yoffset.SETUP[GAME]",                   "0"                             },
+  { "menu.draw_xoffset.SETUP[ENGINES]",                        "0"                             },
+  { "menu.draw_yoffset.SETUP[ENGINES]",                        "0"                             },
+  { "menu.draw_xoffset.SETUP[EDITOR]",                 "0"                             },
+  { "menu.draw_yoffset.SETUP[EDITOR]",                 "0"                             },
+  { "menu.draw_xoffset.SETUP[GRAPHICS]",               "0"                             },
+  { "menu.draw_yoffset.SETUP[GRAPHICS]",               "0"                             },
+  { "menu.draw_xoffset.SETUP[SOUND]",                  "0"                             },
+  { "menu.draw_yoffset.SETUP[SOUND]",                  "0"                             },
+  { "menu.draw_xoffset.SETUP[ARTWORK]",                        "0"                             },
+  { "menu.draw_yoffset.SETUP[ARTWORK]",                        "0"                             },
+  { "menu.draw_xoffset.SETUP[INPUT]",                  "0"                             },
+  { "menu.draw_yoffset.SETUP[INPUT]",                  "0"                             },
+  { "menu.draw_xoffset.SETUP[TOUCH]",                  "0"                             },
+  { "menu.draw_yoffset.SETUP[TOUCH]",                  "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS]",              "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS]",              "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_1]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_1]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_2]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_2]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_3]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_3]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_4]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_4]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_5]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_5]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[SHORTCUTS_6]",            "0"                             },
+  { "menu.draw_yoffset.SETUP[SHORTCUTS_6]",            "0"                             },
+  { "menu.draw_xoffset.SETUP[CHOOSE_ARTWORK]",         "0"                             },
+  { "menu.draw_yoffset.SETUP[CHOOSE_ARTWORK]",         "0"                             },
+  { "menu.draw_xoffset.SETUP[CHOOSE_OTHER]",           "0"                             },
+  { "menu.draw_yoffset.SETUP[CHOOSE_OTHER]",           "0"                             },
+
+  { "menu.scrollbar_xoffset",                          "0"                             },
+
+  { "menu.list.SETUP[CHOOSE_OTHER].align",             "left"                          },
+  { "menu.list.SETUP[CHOOSE_OTHER].valign",            "top"                           },
+
+  { "menu.list_size",                                  "-1"                            },
+  { "menu.list_size.NAMES",                            "-1"                            },
+  { "menu.list_size.LEVELS",                           "-1"                            },
+  { "menu.list_size.LEVELNR",                          "-1"                            },
+  { "menu.list_size.SCORES",                           "-1"                            },
+  { "menu.list_size.INFO",                             "-1"                            },
+  { "menu.list_size.INFO[ELEMENTS]",                   "-1"                            },
+  { "menu.list_size.SETUP",                            "-1"                            },
+
+  { "menu.list_entry_size.INFO[ELEMENTS]",             "-1"                            },
+
+  { "menu.tile_size.INFO[ELEMENTS]",                   "-1"                            },
+
+  { "menu.left_spacing.SCOREINFO",                     "16"                            },
+  { "menu.left_spacing.INFO",                          "16"                            },
+  { "menu.left_spacing.INFO[TITLE]",                   "16"                            },
+  { "menu.left_spacing.INFO[ELEMENTS]",                        "16"                            },
+  { "menu.left_spacing.INFO[MUSIC]",                   "16"                            },
+  { "menu.left_spacing.INFO[CREDITS]",                 "16"                            },
+  { "menu.left_spacing.INFO[PROGRAM]",                 "16"                            },
+  { "menu.left_spacing.INFO[VERSION]",                 "16"                            },
+  { "menu.left_spacing.INFO[LEVELSET]",                        "16"                            },
+  { "menu.left_spacing.SETUP[INPUT]",                  "16"                            },
+
+  { "menu.middle_spacing.INFO[ELEMENTS]",              "16"                            },
+
+  { "menu.right_spacing.SCOREINFO",                    "16"                            },
+  { "menu.right_spacing.INFO",                         "16"                            },
+  { "menu.right_spacing.INFO[TITLE]",                  "16"                            },
+  { "menu.right_spacing.INFO[ELEMENTS]",               "16"                            },
+  { "menu.right_spacing.INFO[MUSIC]",                  "16"                            },
+  { "menu.right_spacing.INFO[CREDITS]",                        "16"                            },
+  { "menu.right_spacing.INFO[PROGRAM]",                        "16"                            },
+  { "menu.right_spacing.INFO[VERSION]",                        "16"                            },
+  { "menu.right_spacing.INFO[LEVELSET]",               "16"                            },
+  { "menu.right_spacing.SETUP[INPUT]",                 "16"                            },
+
+  { "menu.top_spacing.SCOREINFO",                      "100"                           },
+  { "menu.top_spacing.INFO",                           "100"                           },
+  { "menu.top_spacing.INFO[TITLE]",                    "100"                           },
+  { "menu.top_spacing.INFO[ELEMENTS]",                 "100"                           },
+  { "menu.top_spacing.INFO[MUSIC]",                    "100"                           },
+  { "menu.top_spacing.INFO[CREDITS]",                  "100"                           },
+  { "menu.top_spacing.INFO[PROGRAM]",                  "100"                           },
+  { "menu.top_spacing.INFO[VERSION]",                  "100"                           },
+  { "menu.top_spacing.INFO[LEVELSET]",                 "100"                           },
+  { "menu.top_spacing.SETUP[INPUT]",                   "100"                           },
+
+  { "menu.bottom_spacing.SCOREINFO",                   "20"                            },
+  { "menu.bottom_spacing.INFO",                                "20"                            },
+  { "menu.bottom_spacing.INFO[TITLE]",                 "20"                            },
+  { "menu.bottom_spacing.INFO[ELEMENTS]",              "20"                            },
+  { "menu.bottom_spacing.INFO[MUSIC]",                 "20"                            },
+  { "menu.bottom_spacing.INFO[CREDITS]",               "20"                            },
+  { "menu.bottom_spacing.INFO[PROGRAM]",               "20"                            },
+  { "menu.bottom_spacing.INFO[VERSION]",               "20"                            },
+  { "menu.bottom_spacing.INFO[LEVELSET]",              "20"                            },
+  { "menu.bottom_spacing.SETUP[INPUT]",                        "20"                            },
+
+  { "menu.paragraph_spacing.SCOREINFO",                        "-2"                            },
+  { "menu.paragraph_spacing.INFO",                     "-3"                            },
+  { "menu.paragraph_spacing.INFO[TITLE]",              "-3"                            },
+  { "menu.paragraph_spacing.INFO[ELEMENTS]",           "-3"                            },
+  { "menu.paragraph_spacing.INFO[MUSIC]",              "-3"                            },
+  { "menu.paragraph_spacing.INFO[CREDITS]",            "-3"                            },
+  { "menu.paragraph_spacing.INFO[PROGRAM]",            "-3"                            },
+  { "menu.paragraph_spacing.INFO[VERSION]",            "-2"                            },
+  { "menu.paragraph_spacing.INFO[LEVELSET]",           "-3"                            },
+  { "menu.paragraph_spacing.SETUP[INPUT]",             "-1"                            },
+
+  { "menu.headline1_spacing.SCOREINFO",                        "-2"                            },
+  { "menu.headline1_spacing.INFO",                     "-2"                            },
+  { "menu.headline1_spacing.INFO[TITLE]",              "-2"                            },
+  { "menu.headline1_spacing.INFO[ELEMENTS]",           "-2"                            },
+  { "menu.headline1_spacing.INFO[MUSIC]",              "-2"                            },
+  { "menu.headline1_spacing.INFO[CREDITS]",            "-2"                            },
+  { "menu.headline1_spacing.INFO[PROGRAM]",            "-2"                            },
+  { "menu.headline1_spacing.INFO[VERSION]",            "-2"                            },
+  { "menu.headline1_spacing.INFO[LEVELSET]",           "-2"                            },
+  { "menu.headline1_spacing.SETUP[INPUT]",             "-2"                            },
+
+  { "menu.headline2_spacing.SCOREINFO",                        "-1"                            },
+  { "menu.headline2_spacing.INFO",                     "-1"                            },
+  { "menu.headline2_spacing.INFO[TITLE]",              "-1"                            },
+  { "menu.headline2_spacing.INFO[ELEMENTS]",           "-1"                            },
+  { "menu.headline2_spacing.INFO[MUSIC]",              "-1"                            },
+  { "menu.headline2_spacing.INFO[CREDITS]",            "-1"                            },
+  { "menu.headline2_spacing.INFO[PROGRAM]",            "-1"                            },
+  { "menu.headline2_spacing.INFO[VERSION]",            "-1"                            },
+  { "menu.headline2_spacing.INFO[LEVELSET]",           "-1"                            },
+  { "menu.headline2_spacing.SETUP[INPUT]",             "-1"                            },
+
+  { "menu.line_spacing.SCOREINFO",                     "0"                             },
+  { "menu.line_spacing.INFO",                          "0"                             },
+  { "menu.line_spacing.INFO[TITLE]",                   "0"                             },
+  { "menu.line_spacing.INFO[ELEMENTS]",                        "0"                             },
+  { "menu.line_spacing.INFO[MUSIC]",                   "0"                             },
+  { "menu.line_spacing.INFO[CREDITS]",                 "0"                             },
+  { "menu.line_spacing.INFO[PROGRAM]",                 "0"                             },
+  { "menu.line_spacing.INFO[VERSION]",                 "0"                             },
+  { "menu.line_spacing.INFO[LEVELSET]",                        "0"                             },
+  { "menu.line_spacing.SETUP[INPUT]",                  "0"                             },
+
+  { "menu.extra_spacing.SCOREINFO",                    "2"                             },
+  { "menu.extra_spacing.INFO",                         "2"                             },
+  { "menu.extra_spacing.INFO[TITLE]",                  "2"                             },
+  { "menu.extra_spacing.INFO[ELEMENTS]",               "4"                             },
+  { "menu.extra_spacing.INFO[MUSIC]",                  "2"                             },
+  { "menu.extra_spacing.INFO[CREDITS]",                        "2"                             },
+  { "menu.extra_spacing.INFO[PROGRAM]",                        "2"                             },
+  { "menu.extra_spacing.INFO[VERSION]",                        "2"                             },
+  { "menu.extra_spacing.INFO[LEVELSET]",               "2"                             },
+  { "menu.extra_spacing.SETUP[INPUT]",                 "2"                             },
+
+  { "main.button.name.x",                              "0"                             },
+  { "main.button.name.y",                              "64"                            },
+  { "main.button.levels.x",                            "0"                             },
+  { "main.button.levels.y",                            "96"                            },
+  { "main.button.scores.x",                            "0"                             },
+  { "main.button.scores.y",                            "128"                           },
+  { "main.button.editor.x",                            "0"                             },
+  { "main.button.editor.y",                            "160"                           },
+  { "main.button.info.x",                              "0"                             },
+  { "main.button.info.y",                              "192"                           },
+  { "main.button.game.x",                              "0"                             },
+  { "main.button.game.y",                              "224"                           },
+  { "main.button.setup.x",                             "0"                             },
+  { "main.button.setup.y",                             "256"                           },
+  { "main.button.quit.x",                              "0"                             },
+  { "main.button.quit.y",                              "288"                           },
+
+  { "main.button.first_level.x",                       "-1"                            },
+  { "main.button.first_level.y",                       "-1"                            },
+  { "main.button.last_level.x",                                "-1"                            },
+  { "main.button.last_level.y",                                "-1"                            },
+  { "main.button.level_number.x",                      "-1"                            },
+  { "main.button.level_number.y",                      "-1"                            },
+
+  { "main.button.prev_level.x",                                "320"                           },
+  { "main.button.prev_level.y",                                "96"                            },
+  { "main.button.next_level.x",                                "448"                           },
+  { "main.button.next_level.y",                                "96"                            },
+
+  { "main.button.insert_solution.x",                   "-1"                            },
+  { "main.button.insert_solution.y",                   "-1"                            },
+  { "main.button.play_solution.x",                     "-1"                            },
+  { "main.button.play_solution.y",                     "-1"                            },
+
+  { "main.button.levelset_info.x",                     "-1"                            },
+  { "main.button.levelset_info.y",                     "-1"                            },
+
+  { "main.button.switch_ecs_aga.x",                    "-1"                            },
+  { "main.button.switch_ecs_aga.y",                    "-1"                            },
+
+  { "main.text.name.x",                                        "-1"                            },
+  { "main.text.name.y",                                        "-1"                            },
+  { "main.text.name.width",                            "-1"                            },
+  { "main.text.name.height",                           "-1"                            },
+  { "main.text.name.align",                            "left"                          },
+  { "main.text.name.valign",                           "top"                           },
+  { "main.text.name.font",                             "font.menu_1"                   },
+  { "main.text.levels.x",                              "-1"                            },
+  { "main.text.levels.y",                              "-1"                            },
+  { "main.text.levels.width",                          "-1"                            },
+  { "main.text.levels.height",                         "-1"                            },
+  { "main.text.levels.align",                          "left"                          },
+  { "main.text.levels.valign",                         "top"                           },
+  { "main.text.levels.font",                           "font.menu_1"                   },
+  { "main.text.scores.x",                              "-1"                            },
+  { "main.text.scores.y",                              "-1"                            },
+  { "main.text.scores.width",                          "-1"                            },
+  { "main.text.scores.height",                         "-1"                            },
+  { "main.text.scores.align",                          "left"                          },
+  { "main.text.scores.valign",                         "top"                           },
+  { "main.text.scores.font",                           "font.menu_1"                   },
+  { "main.text.editor.x",                              "-1"                            },
+  { "main.text.editor.y",                              "-1"                            },
+  { "main.text.editor.width",                          "-1"                            },
+  { "main.text.editor.height",                         "-1"                            },
+  { "main.text.editor.align",                          "left"                          },
+  { "main.text.editor.valign",                         "top"                           },
+  { "main.text.editor.font",                           "font.menu_1"                   },
+  { "main.text.info.x",                                        "-1"                            },
+  { "main.text.info.y",                                        "-1"                            },
+  { "main.text.info.width",                            "-1"                            },
+  { "main.text.info.height",                           "-1"                            },
+  { "main.text.info.align",                            "left"                          },
+  { "main.text.info.valign",                           "top"                           },
+  { "main.text.info.font",                             "font.menu_1"                   },
+  { "main.text.game.x",                                        "-1"                            },
+  { "main.text.game.y",                                        "-1"                            },
+  { "main.text.game.width",                            "-1"                            },
+  { "main.text.game.height",                           "-1"                            },
+  { "main.text.game.align",                            "left"                          },
+  { "main.text.game.valign",                           "top"                           },
+  { "main.text.game.font",                             "font.menu_1"                   },
+  { "main.text.setup.x",                               "-1"                            },
+  { "main.text.setup.y",                               "-1"                            },
+  { "main.text.setup.width",                           "-1"                            },
+  { "main.text.setup.height",                          "-1"                            },
+  { "main.text.setup.align",                           "left"                          },
+  { "main.text.setup.valign",                          "top"                           },
+  { "main.text.setup.font",                            "font.menu_1"                   },
+  { "main.text.quit.x",                                        "-1"                            },
+  { "main.text.quit.y",                                        "-1"                            },
+  { "main.text.quit.width",                            "-1"                            },
+  { "main.text.quit.height",                           "-1"                            },
+  { "main.text.quit.align",                            "left"                          },
+  { "main.text.quit.valign",                           "top"                           },
+  { "main.text.quit.font",                             "font.menu_1"                   },
+
+  { "main.text.first_level.x",                         "488"                           },
+  { "main.text.first_level.y",                         "98"                            },
+  { "main.text.first_level.align",                     "left"                          },
+  { "main.text.first_level.valign",                    "top"                           },
+  { "main.text.first_level.digits",                    "3"                             },
+  { "main.text.first_level.font",                      "font.text_3"                   },
+  { "main.text.last_level.x",                          "488"                           },
+  { "main.text.last_level.y",                          "112"                           },
+  { "main.text.last_level.align",                      "left"                          },
+  { "main.text.last_level.valign",                     "top"                           },
+  { "main.text.last_level.digits",                     "3"                             },
+  { "main.text.last_level.font",                       "font.text_3"                   },
+  { "main.text.level_number.x",                                "352"                           },
+  { "main.text.level_number.y",                                "96"                            },
+  { "main.text.level_number.align",                    "left"                          },
+  { "main.text.level_number.valign",                   "top"                           },
+  { "main.text.level_number.digits",                   "3"                             },
+  { "main.text.level_number.font",                     "font.value_1"                  },
+  { "main.text.level_info_1.x",                                "272"                           },
+  { "main.text.level_info_1.y",                                "352"                           },
+  { "main.text.level_info_1.align",                    "center"                        },
+  { "main.text.level_info_1.valign",                   "top"                           },
+  { "main.text.level_info_1.chars",                    "-1"                            },
+  { "main.text.level_info_1.font",                     "font.text_1"                   },
+  { "main.text.level_info_2.x",                                "272"                           },
+  { "main.text.level_info_2.y",                                "523"                           },
+  { "main.text.level_info_2.align",                    "center"                        },
+  { "main.text.level_info_2.valign",                   "top"                           },
+  { "main.text.level_info_2.chars",                    "-1"                            },
+  { "main.text.level_info_2.font",                     "font.text_2"                   },
+  { "main.text.level_info_2.font_header",              "font.text_4"                   },
+  { "main.text.level_name.x",                          "-1"                            },
+  { "main.text.level_name.y",                          "-1"                            },
+  { "main.text.level_name.align",                      "left"                          },
+  { "main.text.level_name.valign",                     "top"                           },
+  { "main.text.level_name.chars",                      "-1"                            },
+  { "main.text.level_name.font",                       "font.text_2"                   },
+  { "main.text.level_author.x",                                "-1"                            },
+  { "main.text.level_author.y",                                "-1"                            },
+  { "main.text.level_author.align",                    "left"                          },
+  { "main.text.level_author.valign",                   "top"                           },
+  { "main.text.level_author.chars",                    "-1"                            },
+  { "main.text.level_author.font",                     "font.text_2"                   },
+  { "main.text.level_year.x",                          "-1"                            },
+  { "main.text.level_year.y",                          "-1"                            },
+  { "main.text.level_year.align",                      "left"                          },
+  { "main.text.level_year.valign",                     "top"                           },
+  { "main.text.level_year.digits",                     "-1"                            },
+  { "main.text.level_year.font",                       "font.text_2"                   },
+  { "main.text.level_imported_from.x",                 "-1"                            },
+  { "main.text.level_imported_from.y",                 "-1"                            },
+  { "main.text.level_imported_from.align",             "left"                          },
+  { "main.text.level_imported_from.valign",            "top"                           },
+  { "main.text.level_imported_from.chars",             "-1"                            },
+  { "main.text.level_imported_from.font",              "font.text_2"                   },
+  { "main.text.level_imported_by.x",                   "-1"                            },
+  { "main.text.level_imported_by.y",                   "-1"                            },
+  { "main.text.level_imported_by.align",               "left"                          },
+  { "main.text.level_imported_by.valign",              "top"                           },
+  { "main.text.level_imported_by.chars",               "-1"                            },
+  { "main.text.level_imported_by.font",                        "font.text_2"                   },
+  { "main.text.level_tested_by.x",                     "-1"                            },
+  { "main.text.level_tested_by.y",                     "-1"                            },
+  { "main.text.level_tested_by.align",                 "left"                          },
+  { "main.text.level_tested_by.valign",                        "top"                           },
+  { "main.text.level_tested_by.chars",                 "-1"                            },
+  { "main.text.level_tested_by.font",                  "font.text_2"                   },
+  { "main.text.title_1.x",                             "272"                           },
+  { "main.text.title_1.y",                             "8"                             },
+  { "main.text.title_1.align",                         "center"                        },
+  { "main.text.title_1.valign",                                "top"                           },
+  { "main.text.title_1.font",                          "font.title_1"                  },
+  { "main.text.title_2.x",                             "272"                           },
+  { "main.text.title_2.y",                             "46"                            },
+  { "main.text.title_2.align",                         "center"                        },
+  { "main.text.title_2.valign",                                "top"                           },
+  { "main.text.title_2.font",                          "font.title_2"                  },
+  { "main.text.title_3.x",                             "272"                           },
+  { "main.text.title_3.y",                             "326"                           },
+  { "main.text.title_3.align",                         "center"                        },
+  { "main.text.title_3.valign",                                "top"                           },
+  { "main.text.title_3.font",                          "font.title_2"                  },
+
+  { "main.input.name.x",                               "-1"                            },
+  { "main.input.name.y",                               "-1"                            },
+  { "main.input.name.align",                           "left"                          },
+  { "main.input.name.valign",                          "top"                           },
+  { "main.input.name.font",                            "font.input_1"                  },
+
+  { "main.network_players.x",                          "68"                            },
+  { "main.network_players.y",                          "448"                           },
+  { "main.network_players.align",                      "center"                        },
+  { "main.network_players.valign",                     "middle"                        },
+  { "main.network_players.font",                       "font.main.network_players"     },
+  { "main.network_players.tile_size",                  "16"                            },
+  { "main.network_players.border_size",                        "2"                             },
+
+  { "main.preview_players.x",                          "474"                           },
+  { "main.preview_players.y",                          "448"                           },
+  { "main.preview_players.align",                      "center"                        },
+  { "main.preview_players.valign",                     "middle"                        },
+  { "main.preview_players.tile_size",                  "32"                            },
+  { "main.preview_players.border_size",                        "2"                             },
+  { "main.preview_players.vertical",                   "false"                         },
+  { "main.preview_players.xoffset",                    "-1"                            },
+  { "main.preview_players.yoffset",                    "-1"                            },
+
+  { "setup.button.prev_player.x",                      "320"                           },
+  { "setup.button.prev_player.y",                      "64"                            },
+  { "setup.button.next_player.x",                      "384"                           },
+  { "setup.button.next_player.y",                      "64"                            },
+
+  { "setup.button.touch_back.x",                       "0"                             },
+  { "setup.button.touch_back.y",                       "0"                             },
+  { "setup.button.touch_next.x",                       "-60"                           },
+  { "setup.button.touch_next.y",                       "0"                             },
+  { "setup.button.touch_back2.x",                      "0"                             },
+  { "setup.button.touch_back2.y",                      "-60"                           },
+  { "setup.button.touch_next2.x",                      "-60"                           },
+  { "setup.button.touch_next2.y",                      "-60"                           },
+
+  { "scores.button.prev_level.x",                      "-1"                            },
+  { "scores.button.prev_level.y",                      "-1"                            },
+  { "scores.button.next_level.x",                      "-1"                            },
+  { "scores.button.next_level.y",                      "-1"                            },
+
+  { "scores.button.prev_score.x",                      "-1"                            },
+  { "scores.button.prev_score.y",                      "-1"                            },
+  { "scores.button.next_score.x",                      "-1"                            },
+  { "scores.button.next_score.y",                      "-1"                            },
+
+  { "scores.button.play_tape.x",                       "-1"                            },
+  { "scores.button.play_tape.y",                       "-1"                            },
+
+  { "preview.x",                                       "272"                           },
+  { "preview.y",                                       "380"                           },
+  { "preview.align",                                   "center"                        },
+  { "preview.valign",                                  "top"                           },
+  { "preview.xsize",                                   "66"                            },
+  { "preview.ysize",                                   "34"                            },
+  { "preview.xoffset",                                 "0"                             },
+  { "preview.yoffset",                                 "0"                             },
+  { "preview.tile_size",                               "4"                             },
+  { "preview.step_offset",                             "1"                             },
+  { "preview.step_delay",                              "50"                            },
+  { "preview.anim_mode",                               "default"                       },
+
+  { "door_1.part_1.x",                                 "0"                             },
+  { "door_1.part_1.y",                                 "0"                             },
+  { "door_1.part_1.step_xoffset",                      "3"                             },
+  { "door_1.part_1.step_yoffset",                      "1"                             },
+  { "door_1.part_1.step_delay",                                "10"                            },
+  { "door_1.part_1.start_step",                                "0"                             },
+  { "door_1.part_1.start_step_opening",                        "0"                             },
+  { "door_1.part_1.start_step_closing",                        "0"                             },
+  { "door_1.part_1.draw_masked",                       "true"                          },
+  { "door_1.part_1.draw_order",                                "3"                             },
+  { "door_1.part_2.x",                                 "0"                             },
+  { "door_1.part_2.y",                                 "77"                            },
+  { "door_1.part_2.step_xoffset",                      "3"                             },
+  { "door_1.part_2.step_yoffset",                      "1"                             },
+  { "door_1.part_2.step_delay",                                "10"                            },
+  { "door_1.part_2.start_step",                                "0"                             },
+  { "door_1.part_2.start_step_opening",                        "0"                             },
+  { "door_1.part_2.start_step_closing",                        "0"                             },
+  { "door_1.part_2.draw_masked",                       "true"                          },
+  { "door_1.part_2.draw_order",                                "5"                             },
+  { "door_1.part_3.x",                                 "0"                             },
+  { "door_1.part_3.y",                                 "140"                           },
+  { "door_1.part_3.step_xoffset",                      "3"                             },
+  { "door_1.part_3.step_yoffset",                      "1"                             },
+  { "door_1.part_3.step_delay",                                "10"                            },
+  { "door_1.part_3.start_step",                                "0"                             },
+  { "door_1.part_3.start_step_opening",                        "0"                             },
+  { "door_1.part_3.start_step_closing",                        "0"                             },
+  { "door_1.part_3.draw_masked",                       "true"                          },
+  { "door_1.part_3.draw_order",                                "4"                             },
+  { "door_1.part_4.x",                                 "0"                             },
+  { "door_1.part_4.y",                                 "203"                           },
+  { "door_1.part_4.step_xoffset",                      "3"                             },
+  { "door_1.part_4.step_yoffset",                      "1"                             },
+  { "door_1.part_4.step_delay",                                "10"                            },
+  { "door_1.part_4.start_step",                                "0"                             },
+  { "door_1.part_4.start_step_opening",                        "0"                             },
+  { "door_1.part_4.start_step_closing",                        "0"                             },
+  { "door_1.part_4.draw_masked",                       "true"                          },
+  { "door_1.part_4.draw_order",                                "6"                             },
+  { "door_1.part_5.x",                                 "0"                             },
+  { "door_1.part_5.y",                                 "0"                             },
+  { "door_1.part_5.step_xoffset",                      "-3"                            },
+  { "door_1.part_5.step_yoffset",                      "-1"                            },
+  { "door_1.part_5.step_delay",                                "10"                            },
+  { "door_1.part_5.start_step",                                "0"                             },
+  { "door_1.part_5.start_step_opening",                        "0"                             },
+  { "door_1.part_5.start_step_closing",                        "0"                             },
+  { "door_1.part_5.draw_masked",                       "true"                          },
+  { "door_1.part_5.draw_order",                                "1"                             },
+  { "door_1.part_6.x",                                 "0"                             },
+  { "door_1.part_6.y",                                 "77"                            },
+  { "door_1.part_6.step_xoffset",                      "-3"                            },
+  { "door_1.part_6.step_yoffset",                      "-1"                            },
+  { "door_1.part_6.step_delay",                                "10"                            },
+  { "door_1.part_6.start_step",                                "0"                             },
+  { "door_1.part_6.start_step_opening",                        "0"                             },
+  { "door_1.part_6.start_step_closing",                        "0"                             },
+  { "door_1.part_6.draw_masked",                       "true"                          },
+  { "door_1.part_6.draw_order",                                "7"                             },
+  { "door_1.part_7.x",                                 "0"                             },
+  { "door_1.part_7.y",                                 "140"                           },
+  { "door_1.part_7.step_xoffset",                      "-3"                            },
+  { "door_1.part_7.step_yoffset",                      "-1"                            },
+  { "door_1.part_7.step_delay",                                "10"                            },
+  { "door_1.part_7.start_step",                                "0"                             },
+  { "door_1.part_7.start_step_opening",                        "0"                             },
+  { "door_1.part_7.start_step_closing",                        "0"                             },
+  { "door_1.part_7.draw_masked",                       "true"                          },
+  { "door_1.part_7.draw_order",                                "2"                             },
+  { "door_1.part_8.x",                                 "0"                             },
+  { "door_1.part_8.y",                                 "203"                           },
+  { "door_1.part_8.step_xoffset",                      "-3"                            },
+  { "door_1.part_8.step_yoffset",                      "-1"                            },
+  { "door_1.part_8.step_delay",                                "10"                            },
+  { "door_1.part_8.start_step",                                "0"                             },
+  { "door_1.part_8.start_step_opening",                        "0"                             },
+  { "door_1.part_8.start_step_closing",                        "0"                             },
+  { "door_1.part_8.draw_masked",                       "true"                          },
+  { "door_1.part_8.draw_order",                                "8"                             },
+
+  { "door_2.part_1.x",                                 "0"                             },
+  { "door_2.part_1.y",                                 "0"                             },
+  { "door_2.part_1.step_xoffset",                      "3"                             },
+  { "door_2.part_1.step_yoffset",                      "1"                             },
+  { "door_2.part_1.step_delay",                                "10"                            },
+  { "door_2.part_1.start_step",                                "0"                             },
+  { "door_2.part_1.start_step_opening",                        "0"                             },
+  { "door_2.part_1.start_step_closing",                        "0"                             },
+  { "door_2.part_1.draw_masked",                       "true"                          },
+  { "door_2.part_1.draw_order",                                "2"                             },
+  { "door_2.part_2.x",                                 "0"                             },
+  { "door_2.part_2.y",                                 "50"                            },
+  { "door_2.part_2.step_xoffset",                      "3"                             },
+  { "door_2.part_2.step_yoffset",                      "1"                             },
+  { "door_2.part_2.step_delay",                                "10"                            },
+  { "door_2.part_2.start_step",                                "0"                             },
+  { "door_2.part_2.start_step_opening",                        "0"                             },
+  { "door_2.part_2.start_step_closing",                        "0"                             },
+  { "door_2.part_2.draw_masked",                       "true"                          },
+  { "door_2.part_2.draw_order",                                "3"                             },
+  { "door_2.part_3.x",                                 "0"                             },
+  { "door_2.part_3.y",                                 "0"                             },
+  { "door_2.part_3.step_xoffset",                      "-3"                            },
+  { "door_2.part_3.step_yoffset",                      "-1"                            },
+  { "door_2.part_3.step_delay",                                "10"                            },
+  { "door_2.part_3.start_step",                                "0"                             },
+  { "door_2.part_3.start_step_opening",                        "0"                             },
+  { "door_2.part_3.start_step_closing",                        "0"                             },
+  { "door_2.part_3.draw_masked",                       "true"                          },
+  { "door_2.part_3.draw_order",                                "1"                             },
+  { "door_2.part_4.x",                                 "0"                             },
+  { "door_2.part_4.y",                                 "50"                            },
+  { "door_2.part_4.step_xoffset",                      "-3"                            },
+  { "door_2.part_4.step_yoffset",                      "-1"                            },
+  { "door_2.part_4.step_delay",                                "10"                            },
+  { "door_2.part_4.start_step",                                "0"                             },
+  { "door_2.part_4.start_step_opening",                        "0"                             },
+  { "door_2.part_4.start_step_closing",                        "0"                             },
+  { "door_2.part_4.draw_masked",                       "true"                          },
+  { "door_2.part_4.draw_order",                                "4"                             },
+  { "door_2.part_5.x",                                 "-1"                            },
+  { "door_2.part_5.y",                                 "-1"                            },
+  { "door_2.part_5.step_xoffset",                      "0"                             },
+  { "door_2.part_5.step_yoffset",                      "0"                             },
+  { "door_2.part_5.step_delay",                                "0"                             },
+  { "door_2.part_5.start_step",                                "0"                             },
+  { "door_2.part_5.start_step_opening",                        "0"                             },
+  { "door_2.part_5.start_step_closing",                        "0"                             },
+  { "door_2.part_5.draw_masked",                       "true"                          },
+  { "door_2.part_5.draw_order",                                "0"                             },
+  { "door_2.part_6.x",                                 "-1"                            },
+  { "door_2.part_6.y",                                 "-1"                            },
+  { "door_2.part_6.step_xoffset",                      "0"                             },
+  { "door_2.part_6.step_yoffset",                      "0"                             },
+  { "door_2.part_6.step_delay",                                "0"                             },
+  { "door_2.part_6.start_step",                                "0"                             },
+  { "door_2.part_6.start_step_opening",                        "0"                             },
+  { "door_2.part_6.start_step_closing",                        "0"                             },
+  { "door_2.part_6.draw_masked",                       "true"                          },
+  { "door_2.part_6.draw_order",                                "0"                             },
+  { "door_2.part_7.x",                                 "-1"                            },
+  { "door_2.part_7.y",                                 "-1"                            },
+  { "door_2.part_7.step_xoffset",                      "0"                             },
+  { "door_2.part_7.step_yoffset",                      "0"                             },
+  { "door_2.part_7.step_delay",                                "0"                             },
+  { "door_2.part_7.start_step",                                "0"                             },
+  { "door_2.part_7.start_step_opening",                        "0"                             },
+  { "door_2.part_7.start_step_closing",                        "0"                             },
+  { "door_2.part_7.draw_masked",                       "true"                          },
+  { "door_2.part_7.draw_order",                                "0"                             },
+  { "door_2.part_8.x",                                 "-1"                            },
+  { "door_2.part_8.y",                                 "-1"                            },
+  { "door_2.part_8.step_xoffset",                      "0"                             },
+  { "door_2.part_8.step_yoffset",                      "0"                             },
+  { "door_2.part_8.step_delay",                                "0"                             },
+  { "door_2.part_8.start_step",                                "0"                             },
+  { "door_2.part_8.start_step_opening",                        "0"                             },
+  { "door_2.part_8.start_step_closing",                        "0"                             },
+  { "door_2.part_8.draw_masked",                       "true"                          },
+  { "door_2.part_8.draw_order",                                "0"                             },
+
+  { "door_1.panel.x",                                  "0"                             },
+  { "door_1.panel.y",                                  "0"                             },
+  { "door_1.panel.step_xoffset",                       "0"                             },
+  { "door_1.panel.step_yoffset",                       "1"                             },
+  { "door_1.panel.step_delay",                         "10"                            },
+  { "door_1.panel.start_step",                         "246"                           },
+  { "door_1.panel.start_step_opening",                 "0"                             },
+  { "door_1.panel.start_step_closing",                 "0"                             },
+  { "door_1.panel.draw_masked",                                "false"                         },
+  { "door_1.panel.draw_order",                         "0"                             },
+
+  { "door_2.panel.x",                                  "0"                             },
+  { "door_2.panel.y",                                  "0"                             },
+  { "door_2.panel.step_xoffset",                       "0"                             },
+  { "door_2.panel.step_yoffset",                       "1"                             },
+  { "door_2.panel.step_delay",                         "10"                            },
+  { "door_2.panel.start_step",                         "66"                            },
+  { "door_2.panel.start_step_opening",                 "0"                             },
+  { "door_2.panel.start_step_closing",                 "0"                             },
+  { "door_2.panel.draw_masked",                                "false"                         },
+  { "door_2.panel.draw_order",                         "0"                             },
+
+  { "door_1.width",                                    "-1"                            },
+  { "door_1.height",                                   "-1"                            },
+  { "door_1.step_offset",                              "2"                             },
+  { "door_1.step_delay",                               "10"                            },
+  { "door_1.post_delay",                               "100"                           },
+  { "door_1.anim_mode",                                        "default"                       },
+
+  { "door_2.width",                                    "-1"                            },
+  { "door_2.height",                                   "-1"                            },
+  { "door_2.step_offset",                              "2"                             },
+  { "door_2.step_delay",                               "10"                            },
+  { "door_2.post_delay",                               "100"                           },
+  { "door_2.anim_mode",                                        "default"                       },
+
+  { "game.panel.level_number.x",                       "51"                            },
+  { "game.panel.level_number.y",                       "20"                            },
+  { "game.panel.level_number.align",                   "center"                        },
+  { "game.panel.level_number.valign",                  "top"                           },
+  { "game.panel.level_number.digits",                  "-1"                            },
+  { "game.panel.level_number.font",                    "font.text_2"                   },
+  { "game.panel.level_number.font_narrow",             "font.text_1"                   },
+  { "game.panel.level_number.draw_masked",             "true"                          },
+  { "game.panel.level_number.draw_order",              "0"                             },
+  { "game.panel.level_number.class",                   "none"                          },
+  { "game.panel.level_number.style",                   "none"                          },
+
+  { "game.panel.gems.x",                               "50"                            },
+  { "game.panel.gems.y",                               "54"                            },
+  { "game.panel.gems.align",                           "center"                        },
+  { "game.panel.gems.valign",                          "top"                           },
+  { "game.panel.gems.digits",                          "3"                             },
+  { "game.panel.gems.font",                            "font.text_2"                   },
+  { "game.panel.gems.draw_masked",                     "true"                          },
+  { "game.panel.gems.draw_order",                      "0"                             },
+  { "game.panel.gems.class",                           "none"                          },
+  { "game.panel.gems.style",                           "none"                          },
+
+  { "game.panel.gems_needed.x",                                "-1"                            },
+  { "game.panel.gems_needed.y",                                "-1"                            },
+  { "game.panel.gems_needed.align",                    "left"                          },
+  { "game.panel.gems_needed.valign",                   "top"                           },
+  { "game.panel.gems_needed.digits",                   "-1"                            },
+  { "game.panel.gems_needed.font",                     "font.text_2"                   },
+  { "game.panel.gems_needed.draw_masked",              "true"                          },
+  { "game.panel.gems_needed.draw_order",               "0"                             },
+  { "game.panel.gems_needed.class",                    "none"                          },
+  { "game.panel.gems_needed.style",                    "none"                          },
+
+  { "game.panel.gems_collected.x",                     "-1"                            },
+  { "game.panel.gems_collected.y",                     "-1"                            },
+  { "game.panel.gems_collected.align",                 "left"                          },
+  { "game.panel.gems_collected.valign",                        "top"                           },
+  { "game.panel.gems_collected.digits",                        "-1"                            },
+  { "game.panel.gems_collected.font",                  "font.text_2"                   },
+  { "game.panel.gems_collected.draw_masked",           "true"                          },
+  { "game.panel.gems_collected.draw_order",            "0"                             },
+  { "game.panel.gems_collected.class",                 "none"                          },
+  { "game.panel.gems_collected.style",                 "none"                          },
+
+  { "game.panel.gems_score.x",                         "-1"                            },
+  { "game.panel.gems_score.y",                         "-1"                            },
+  { "game.panel.gems_score.align",                     "left"                          },
+  { "game.panel.gems_score.valign",                    "top"                           },
+  { "game.panel.gems_score.digits",                    "-1"                            },
+  { "game.panel.gems_score.font",                      "font.text_2"                   },
+  { "game.panel.gems_score.draw_masked",               "true"                          },
+  { "game.panel.gems_score.draw_order",                        "0"                             },
+  { "game.panel.gems_score.class",                     "none"                          },
+  { "game.panel.gems_score.style",                     "none"                          },
+
+  { "game.panel.inventory_count.x",                    "50"                            },
+  { "game.panel.inventory_count.y",                    "89"                            },
+  { "game.panel.inventory_count.align",                        "center"                        },
+  { "game.panel.inventory_count.valign",               "top"                           },
+  { "game.panel.inventory_count.digits",               "-1"                            },
+  { "game.panel.inventory_count.font",                 "font.text_2"                   },
+  { "game.panel.inventory_count.font_narrow",          "font.text_1"                   },
+  { "game.panel.inventory_count.draw_masked",          "true"                          },
+  { "game.panel.inventory_count.draw_order",           "0"                             },
+  { "game.panel.inventory_count.class",                        "none"                          },
+  { "game.panel.inventory_count.style",                        "none"                          },
+
+  { "game.panel.inventory_first_1.x",                  "-1"                            },
+  { "game.panel.inventory_first_1.y",                  "-1"                            },
+  { "game.panel.inventory_first_1.tile_size",          "16"                            },
+  { "game.panel.inventory_first_1.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_1.draw_order",         "0"                             },
+  { "game.panel.inventory_first_1.class",              "none"                          },
+  { "game.panel.inventory_first_1.style",              "none"                          },
+  { "game.panel.inventory_first_2.x",                  "-1"                            },
+  { "game.panel.inventory_first_2.y",                  "-1"                            },
+  { "game.panel.inventory_first_2.tile_size",          "16"                            },
+  { "game.panel.inventory_first_2.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_2.draw_order",         "0"                             },
+  { "game.panel.inventory_first_2.class",              "none"                          },
+  { "game.panel.inventory_first_2.style",              "none"                          },
+  { "game.panel.inventory_first_3.x",                  "-1"                            },
+  { "game.panel.inventory_first_3.y",                  "-1"                            },
+  { "game.panel.inventory_first_3.tile_size",          "16"                            },
+  { "game.panel.inventory_first_3.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_3.draw_order",         "0"                             },
+  { "game.panel.inventory_first_3.class",              "none"                          },
+  { "game.panel.inventory_first_3.style",              "none"                          },
+  { "game.panel.inventory_first_4.x",                  "-1"                            },
+  { "game.panel.inventory_first_4.y",                  "-1"                            },
+  { "game.panel.inventory_first_4.tile_size",          "16"                            },
+  { "game.panel.inventory_first_4.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_4.draw_order",         "0"                             },
+  { "game.panel.inventory_first_4.class",              "none"                          },
+  { "game.panel.inventory_first_4.style",              "none"                          },
+  { "game.panel.inventory_first_5.x",                  "-1"                            },
+  { "game.panel.inventory_first_5.y",                  "-1"                            },
+  { "game.panel.inventory_first_5.tile_size",          "16"                            },
+  { "game.panel.inventory_first_5.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_5.draw_order",         "0"                             },
+  { "game.panel.inventory_first_5.class",              "none"                          },
+  { "game.panel.inventory_first_5.style",              "none"                          },
+  { "game.panel.inventory_first_6.x",                  "-1"                            },
+  { "game.panel.inventory_first_6.y",                  "-1"                            },
+  { "game.panel.inventory_first_6.tile_size",          "16"                            },
+  { "game.panel.inventory_first_6.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_6.draw_order",         "0"                             },
+  { "game.panel.inventory_first_6.class",              "none"                          },
+  { "game.panel.inventory_first_6.style",              "none"                          },
+  { "game.panel.inventory_first_7.x",                  "-1"                            },
+  { "game.panel.inventory_first_7.y",                  "-1"                            },
+  { "game.panel.inventory_first_7.tile_size",          "16"                            },
+  { "game.panel.inventory_first_7.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_7.draw_order",         "0"                             },
+  { "game.panel.inventory_first_7.class",              "none"                          },
+  { "game.panel.inventory_first_7.style",              "none"                          },
+  { "game.panel.inventory_first_8.x",                  "-1"                            },
+  { "game.panel.inventory_first_8.y",                  "-1"                            },
+  { "game.panel.inventory_first_8.tile_size",          "16"                            },
+  { "game.panel.inventory_first_8.draw_masked",                "false"                         },
+  { "game.panel.inventory_first_8.draw_order",         "0"                             },
+  { "game.panel.inventory_first_8.class",              "none"                          },
+  { "game.panel.inventory_first_8.style",              "none"                          },
+
+  { "game.panel.inventory_last_1.x",                   "-1"                            },
+  { "game.panel.inventory_last_1.y",                   "-1"                            },
+  { "game.panel.inventory_last_1.tile_size",           "16"                            },
+  { "game.panel.inventory_last_1.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_1.draw_order",          "0"                             },
+  { "game.panel.inventory_last_1.class",               "none"                          },
+  { "game.panel.inventory_last_1.style",               "none"                          },
+  { "game.panel.inventory_last_2.x",                   "-1"                            },
+  { "game.panel.inventory_last_2.y",                   "-1"                            },
+  { "game.panel.inventory_last_2.tile_size",           "16"                            },
+  { "game.panel.inventory_last_2.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_2.draw_order",          "0"                             },
+  { "game.panel.inventory_last_2.class",               "none"                          },
+  { "game.panel.inventory_last_2.style",               "none"                          },
+  { "game.panel.inventory_last_3.x",                   "-1"                            },
+  { "game.panel.inventory_last_3.y",                   "-1"                            },
+  { "game.panel.inventory_last_3.tile_size",           "16"                            },
+  { "game.panel.inventory_last_3.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_3.draw_order",          "0"                             },
+  { "game.panel.inventory_last_3.class",               "none"                          },
+  { "game.panel.inventory_last_3.style",               "none"                          },
+  { "game.panel.inventory_last_4.x",                   "-1"                            },
+  { "game.panel.inventory_last_4.y",                   "-1"                            },
+  { "game.panel.inventory_last_4.tile_size",           "16"                            },
+  { "game.panel.inventory_last_4.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_4.draw_order",          "0"                             },
+  { "game.panel.inventory_last_4.class",               "none"                          },
+  { "game.panel.inventory_last_4.style",               "none"                          },
+  { "game.panel.inventory_last_5.x",                   "-1"                            },
+  { "game.panel.inventory_last_5.y",                   "-1"                            },
+  { "game.panel.inventory_last_5.tile_size",           "16"                            },
+  { "game.panel.inventory_last_5.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_5.draw_order",          "0"                             },
+  { "game.panel.inventory_last_5.class",               "none"                          },
+  { "game.panel.inventory_last_5.style",               "none"                          },
+  { "game.panel.inventory_last_6.x",                   "-1"                            },
+  { "game.panel.inventory_last_6.y",                   "-1"                            },
+  { "game.panel.inventory_last_6.tile_size",           "16"                            },
+  { "game.panel.inventory_last_6.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_6.draw_order",          "0"                             },
+  { "game.panel.inventory_last_6.class",               "none"                          },
+  { "game.panel.inventory_last_6.style",               "none"                          },
+  { "game.panel.inventory_last_7.x",                   "-1"                            },
+  { "game.panel.inventory_last_7.y",                   "-1"                            },
+  { "game.panel.inventory_last_7.tile_size",           "16"                            },
+  { "game.panel.inventory_last_7.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_7.draw_order",          "0"                             },
+  { "game.panel.inventory_last_7.class",               "none"                          },
+  { "game.panel.inventory_last_7.style",               "none"                          },
+  { "game.panel.inventory_last_8.x",                   "-1"                            },
+  { "game.panel.inventory_last_8.y",                   "-1"                            },
+  { "game.panel.inventory_last_8.tile_size",           "16"                            },
+  { "game.panel.inventory_last_8.draw_masked",         "false"                         },
+  { "game.panel.inventory_last_8.draw_order",          "0"                             },
+  { "game.panel.inventory_last_8.class",               "none"                          },
+  { "game.panel.inventory_last_8.style",               "none"                          },
+
+  { "game.panel.key_1.x",                              "18"                            },
+  { "game.panel.key_1.y",                              "123"                           },
+  { "game.panel.key_1.tile_size",                      "16"                            },
+  { "game.panel.key_1.draw_masked",                    "false"                         },
+  { "game.panel.key_1.draw_order",                     "0"                             },
+  { "game.panel.key_1.class",                          "none"                          },
+  { "game.panel.key_1.style",                          "none"                          },
+  { "game.panel.key_2.x",                              "34"                            },
+  { "game.panel.key_2.y",                              "123"                           },
+  { "game.panel.key_2.tile_size",                      "16"                            },
+  { "game.panel.key_2.draw_masked",                    "false"                         },
+  { "game.panel.key_2.draw_order",                     "0"                             },
+  { "game.panel.key_2.class",                          "none"                          },
+  { "game.panel.key_2.style",                          "none"                          },
+  { "game.panel.key_3.x",                              "50"                            },
+  { "game.panel.key_3.y",                              "123"                           },
+  { "game.panel.key_3.tile_size",                      "16"                            },
+  { "game.panel.key_3.draw_masked",                    "false"                         },
+  { "game.panel.key_3.draw_order",                     "0"                             },
+  { "game.panel.key_3.class",                          "none"                          },
+  { "game.panel.key_3.style",                          "none"                          },
+  { "game.panel.key_4.x",                              "66"                            },
+  { "game.panel.key_4.y",                              "123"                           },
+  { "game.panel.key_4.tile_size",                      "16"                            },
+  { "game.panel.key_4.draw_masked",                    "false"                         },
+  { "game.panel.key_4.draw_order",                     "0"                             },
+  { "game.panel.key_4.class",                          "none"                          },
+  { "game.panel.key_4.style",                          "none"                          },
+  { "game.panel.key_5.x",                              "-1"                            },
+  { "game.panel.key_5.y",                              "-1"                            },
+  { "game.panel.key_5.tile_size",                      "16"                            },
+  { "game.panel.key_5.draw_masked",                    "false"                         },
+  { "game.panel.key_5.draw_order",                     "0"                             },
+  { "game.panel.key_5.class",                          "none"                          },
+  { "game.panel.key_5.style",                          "none"                          },
+  { "game.panel.key_6.x",                              "-1"                            },
+  { "game.panel.key_6.y",                              "-1"                            },
+  { "game.panel.key_6.tile_size",                      "16"                            },
+  { "game.panel.key_6.draw_masked",                    "false"                         },
+  { "game.panel.key_6.draw_order",                     "0"                             },
+  { "game.panel.key_6.class",                          "none"                          },
+  { "game.panel.key_6.style",                          "none"                          },
+  { "game.panel.key_7.x",                              "-1"                            },
+  { "game.panel.key_7.y",                              "-1"                            },
+  { "game.panel.key_7.tile_size",                      "16"                            },
+  { "game.panel.key_7.draw_masked",                    "false"                         },
+  { "game.panel.key_7.draw_order",                     "0"                             },
+  { "game.panel.key_7.class",                          "none"                          },
+  { "game.panel.key_7.style",                          "none"                          },
+  { "game.panel.key_8.x",                              "-1"                            },
+  { "game.panel.key_8.y",                              "-1"                            },
+  { "game.panel.key_8.tile_size",                      "16"                            },
+  { "game.panel.key_8.draw_masked",                    "false"                         },
+  { "game.panel.key_8.draw_order",                     "0"                             },
+  { "game.panel.key_8.class",                          "none"                          },
+  { "game.panel.key_8.style",                          "none"                          },
+  { "game.panel.key_white.x",                          "-1"                            },
+  { "game.panel.key_white.y",                          "-1"                            },
+  { "game.panel.key_white.tile_size",                  "16"                            },
+  { "game.panel.key_white.draw_masked",                        "false"                         },
+  { "game.panel.key_white.draw_order",                 "0"                             },
+  { "game.panel.key_white.class",                      "none"                          },
+  { "game.panel.key_white.style",                      "none"                          },
+  { "game.panel.key_white_count.x",                    "-1"                            },
+  { "game.panel.key_white_count.y",                    "-1"                            },
+  { "game.panel.key_white_count.align",                        "left"                          },
+  { "game.panel.key_white_count.valign",               "top"                           },
+  { "game.panel.key_white_count.digits",               "-1"                            },
+  { "game.panel.key_white_count.font",                 "font.text_2"                   },
+  { "game.panel.key_white_count.draw_masked",          "true"                          },
+  { "game.panel.key_white_count.draw_order",           "0"                             },
+  { "game.panel.key_white_count.class",                        "none"                          },
+  { "game.panel.key_white_count.style",                        "none"                          },
+
+  { "game.panel.score.x",                              "50"                            },
+  { "game.panel.score.y",                              "159"                           },
+  { "game.panel.score.align",                          "center"                        },
+  { "game.panel.score.valign",                         "top"                           },
+  { "game.panel.score.digits",                         "-1"                            },
+  { "game.panel.score.font",                           "font.text_2"                   },
+  { "game.panel.score.font_narrow",                    "font.text_1"                   },
+  { "game.panel.score.draw_masked",                    "true"                          },
+  { "game.panel.score.draw_order",                     "0"                             },
+  { "game.panel.score.class",                          "none"                          },
+  { "game.panel.score.style",                          "none"                          },
+
+  { "game.panel.highscore.x",                          "-1"                            },
+  { "game.panel.highscore.y",                          "-1"                            },
+  { "game.panel.highscore.align",                      "left"                          },
+  { "game.panel.highscore.valign",                     "top"                           },
+  { "game.panel.highscore.digits",                     "-1"                            },
+  { "game.panel.highscore.font",                       "font.text_2"                   },
+  { "game.panel.highscore.font_narrow",                        "font.text_1"                   },
+  { "game.panel.highscore.draw_masked",                        "true"                          },
+  { "game.panel.highscore.draw_order",                 "0"                             },
+  { "game.panel.highscore.class",                      "none"                          },
+  { "game.panel.highscore.style",                      "none"                          },
+
+  { "game.panel.time.x",                               "50"                            },
+  { "game.panel.time.y",                               "194"                           },
+  { "game.panel.time.align",                           "center"                        },
+  { "game.panel.time.valign",                          "top"                           },
+  { "game.panel.time.digits",                          "-1"                            },
+  { "game.panel.time.font",                            "font.text_2"                   },
+  { "game.panel.time.font_narrow",                     "font.text_1"                   },
+  { "game.panel.time.draw_masked",                     "true"                          },
+  { "game.panel.time.draw_order",                      "0"                             },
+  { "game.panel.time.class",                           "none"                          },
+  { "game.panel.time.style",                           "none"                          },
+
+  { "game.panel.time_hh.x",                            "-1"                            },
+  { "game.panel.time_hh.y",                            "-1"                            },
+  { "game.panel.time_hh.align",                                "left"                          },
+  { "game.panel.time_hh.valign",                       "top"                           },
+  { "game.panel.time_hh.digits",                       "2"                             },
+  { "game.panel.time_hh.font",                         "font.text_2"                   },
+  { "game.panel.time_hh.draw_masked",                  "true"                          },
+  { "game.panel.time_hh.draw_order",                   "0"                             },
+  { "game.panel.time_hh.class",                                "none"                          },
+  { "game.panel.time_hh.style",                                "none"                          },
+  { "game.panel.time_mm.x",                            "-1"                            },
+  { "game.panel.time_mm.y",                            "-1"                            },
+  { "game.panel.time_mm.align",                                "left"                          },
+  { "game.panel.time_mm.valign",                       "top"                           },
+  { "game.panel.time_mm.digits",                       "2"                             },
+  { "game.panel.time_mm.font",                         "font.text_2"                   },
+  { "game.panel.time_mm.draw_masked",                  "true"                          },
+  { "game.panel.time_mm.draw_order",                   "0"                             },
+  { "game.panel.time_mm.class",                                "none"                          },
+  { "game.panel.time_mm.style",                                "none"                          },
+  { "game.panel.time_ss.x",                            "-1"                            },
+  { "game.panel.time_ss.y",                            "-1"                            },
+  { "game.panel.time_ss.align",                                "left"                          },
+  { "game.panel.time_ss.valign",                       "top"                           },
+  { "game.panel.time_ss.digits",                       "2"                             },
+  { "game.panel.time_ss.font",                         "font.text_2"                   },
+  { "game.panel.time_ss.draw_masked",                  "true"                          },
+  { "game.panel.time_ss.draw_order",                   "0"                             },
+  { "game.panel.time_ss.class",                                "none"                          },
+  { "game.panel.time_ss.style",                                "none"                          },
+
+  { "game.panel.time_anim.x",                          "5"                             },
+  { "game.panel.time_anim.y",                          "72"                            },
+  { "game.panel.time_anim.direction",                  "right"                         },
+  { "game.panel.time_anim.class",                      "mm_engine_only"                },
+  { "game.panel.time_anim.style",                      "none"                          },
+
+  { "game.panel.health.x",                             "-1"                            },
+  { "game.panel.health.y",                             "-1"                            },
+  { "game.panel.health.align",                         "center"                        },
+  { "game.panel.health.valign",                                "top"                           },
+  { "game.panel.health.digits",                                "-1"                            },
+  { "game.panel.health.font",                          "font.text_2"                   },
+  { "game.panel.health.font_narrow",                   "font.text_1"                   },
+  { "game.panel.health.draw_masked",                   "true"                          },
+  { "game.panel.health.draw_order",                    "0"                             },
+  { "game.panel.health.class",                         "none"                          },
+  { "game.panel.health.style",                         "none"                          },
+
+  { "game.panel.health_anim.x",                                "5"                             },
+  { "game.panel.health_anim.y",                                "107"                           },
+  { "game.panel.health_anim.direction",                        "right"                         },
+  { "game.panel.health_anim.class",                    "mm_engine_only"                },
+  { "game.panel.health_anim.style",                    "reverse"                       },
+
+  { "game.panel.frame.x",                              "-1"                            },
+  { "game.panel.frame.y",                              "-1"                            },
+  { "game.panel.frame.align",                          "left"                          },
+  { "game.panel.frame.valign",                         "top"                           },
+  { "game.panel.frame.digits",                         "-1"                            },
+  { "game.panel.frame.font",                           "font.text_2"                   },
+  { "game.panel.frame.draw_masked",                    "true"                          },
+  { "game.panel.frame.draw_order",                     "0"                             },
+  { "game.panel.frame.class",                          "none"                          },
+  { "game.panel.frame.style",                          "none"                          },
+
+  { "game.panel.shield_normal.x",                      "-1"                            },
+  { "game.panel.shield_normal.y",                      "-1"                            },
+  { "game.panel.shield_normal.tile_size",              "16"                            },
+  { "game.panel.shield_normal.draw_masked",            "false"                         },
+  { "game.panel.shield_normal.draw_order",             "0"                             },
+  { "game.panel.shield_normal_time.x",                 "-1"                            },
+  { "game.panel.shield_normal_time.y",                 "-1"                            },
+  { "game.panel.shield_normal_time.align",             "left"                          },
+  { "game.panel.shield_normal_time.valign",            "top"                           },
+  { "game.panel.shield_normal_time.digits",            "-1"                            },
+  { "game.panel.shield_normal_time.font",              "font.text_2"                   },
+  { "game.panel.shield_normal_time.draw_masked",       "true"                          },
+  { "game.panel.shield_normal_time.draw_order",                "0"                             },
+  { "game.panel.shield_normal_time.class",             "none"                          },
+  { "game.panel.shield_normal_time.style",             "none"                          },
+  { "game.panel.shield_deadly.x",                      "-1"                            },
+  { "game.panel.shield_deadly.y",                      "-1"                            },
+  { "game.panel.shield_deadly.tile_size",              "16"                            },
+  { "game.panel.shield_deadly.draw_masked",            "false"                         },
+  { "game.panel.shield_deadly.draw_order",             "0"                             },
+  { "game.panel.shield_deadly_time.x",                 "-1"                            },
+  { "game.panel.shield_deadly_time.y",                 "-1"                            },
+  { "game.panel.shield_deadly_time.align",             "left"                          },
+  { "game.panel.shield_deadly_time.valign",            "top"                           },
+  { "game.panel.shield_deadly_time.digits",            "-1"                            },
+  { "game.panel.shield_deadly_time.font",              "font.text_2"                   },
+  { "game.panel.shield_deadly_time.draw_masked",       "true"                          },
+  { "game.panel.shield_deadly_time.draw_order",                "0"                             },
+  { "game.panel.shield_deadly_time.class",             "none"                          },
+  { "game.panel.shield_deadly_time.style",             "none"                          },
+
+  { "game.panel.exit.x",                               "-1"                            },
+  { "game.panel.exit.y",                               "-1"                            },
+  { "game.panel.exit.tile_size",                       "16"                            },
+  { "game.panel.exit.draw_masked",                     "false"                         },
+  { "game.panel.exit.draw_order",                      "0"                             },
+  { "game.panel.exit.class",                           "none"                          },
+  { "game.panel.exit.style",                           "none"                          },
+
+  { "game.panel.emc_magic_ball.x",                     "-1"                            },
+  { "game.panel.emc_magic_ball.y",                     "-1"                            },
+  { "game.panel.emc_magic_ball.tile_size",             "16"                            },
+  { "game.panel.emc_magic_ball.draw_masked",           "false"                         },
+  { "game.panel.emc_magic_ball.draw_order",            "0"                             },
+  { "game.panel.emc_magic_ball_switch.x",              "-1"                            },
+  { "game.panel.emc_magic_ball_switch.y",              "-1"                            },
+  { "game.panel.emc_magic_ball_switch.tile_size",      "16"                            },
+  { "game.panel.emc_magic_ball_switch.draw_masked",    "true"                          },
+  { "game.panel.emc_magic_ball_switch.draw_order",     "0"                             },
+  { "game.panel.emc_magic_ball_switch.class",          "none"                          },
+  { "game.panel.emc_magic_ball_switch.style",          "none"                          },
+
+  { "game.panel.light_switch.x",                       "-1"                            },
+  { "game.panel.light_switch.y",                       "-1"                            },
+  { "game.panel.light_switch.tile_size",               "16"                            },
+  { "game.panel.light_switch.draw_masked",             "false"                         },
+  { "game.panel.light_switch.draw_order",              "0"                             },
+  { "game.panel.light_switch_time.x",                  "-1"                            },
+  { "game.panel.light_switch_time.y",                  "-1"                            },
+  { "game.panel.light_switch_time.align",              "left"                          },
+  { "game.panel.light_switch_time.valign",             "top"                           },
+  { "game.panel.light_switch_time.digits",             "-1"                            },
+  { "game.panel.light_switch_time.font",               "font.text_2"                   },
+  { "game.panel.light_switch_time.draw_masked",                "true"                          },
+  { "game.panel.light_switch_time.draw_order",         "0"                             },
+  { "game.panel.light_switch_time.class",              "none"                          },
+  { "game.panel.light_switch_time.style",              "none"                          },
+
+  { "game.panel.timegate_switch.x",                    "-1"                            },
+  { "game.panel.timegate_switch.y",                    "-1"                            },
+  { "game.panel.timegate_switch.tile_size",            "16"                            },
+  { "game.panel.timegate_switch.draw_masked",          "false"                         },
+  { "game.panel.timegate_switch.draw_order",           "0"                             },
+  { "game.panel.timegate_switch_time.x",               "-1"                            },
+  { "game.panel.timegate_switch_time.y",               "-1"                            },
+  { "game.panel.timegate_switch_time.align",           "left"                          },
+  { "game.panel.timegate_switch_time.valign",          "top"                           },
+  { "game.panel.timegate_switch_time.digits",          "-1"                            },
+  { "game.panel.timegate_switch_time.font",            "font.text_2"                   },
+  { "game.panel.timegate_switch_time.draw_masked",     "true"                          },
+  { "game.panel.timegate_switch_time.draw_order",      "0"                             },
+  { "game.panel.timegate_switch_time.class",           "none"                          },
+  { "game.panel.timegate_switch_time.style",           "none"                          },
+
+  { "game.panel.switchgate_switch.x",                  "-1"                            },
+  { "game.panel.switchgate_switch.y",                  "-1"                            },
+  { "game.panel.switchgate_switch.tile_size",          "16"                            },
+  { "game.panel.switchgate_switch.draw_masked",                "false"                         },
+  { "game.panel.switchgate_switch.draw_order",         "0"                             },
+  { "game.panel.switchgate_switch.class",              "none"                          },
+  { "game.panel.switchgate_switch.style",              "none"                          },
+
+  { "game.panel.emc_lenses.x",                         "-1"                            },
+  { "game.panel.emc_lenses.y",                         "-1"                            },
+  { "game.panel.emc_lenses.tile_size",                 "16"                            },
+  { "game.panel.emc_lenses.draw_masked",               "false"                         },
+  { "game.panel.emc_lenses.draw_order",                        "0"                             },
+  { "game.panel.emc_lenses.class",                     "none"                          },
+  { "game.panel.emc_lenses.style",                     "none"                          },
+  { "game.panel.emc_lenses_time.x",                    "-1"                            },
+  { "game.panel.emc_lenses_time.y",                    "-1"                            },
+  { "game.panel.emc_lenses_time.align",                        "left"                          },
+  { "game.panel.emc_lenses_time.valign",               "top"                           },
+  { "game.panel.emc_lenses_time.digits",               "-1"                            },
+  { "game.panel.emc_lenses_time.font",                 "font.text_2"                   },
+  { "game.panel.emc_lenses_time.draw_masked",          "true"                          },
+  { "game.panel.emc_lenses_time.draw_order",           "0"                             },
+  { "game.panel.emc_lenses_time.class",                        "none"                          },
+  { "game.panel.emc_lenses_time.style",                        "none"                          },
+
+  { "game.panel.emc_magnifier.x",                      "-1"                            },
+  { "game.panel.emc_magnifier.y",                      "-1"                            },
+  { "game.panel.emc_magnifier.tile_size",              "16"                            },
+  { "game.panel.emc_magnifier.draw_masked",            "false"                         },
+  { "game.panel.emc_magnifier.draw_order",             "0"                             },
+  { "game.panel.emc_magnifier.class",                  "none"                          },
+  { "game.panel.emc_magnifier.style",                  "none"                          },
+  { "game.panel.emc_magnifier_time.x",                 "-1"                            },
+  { "game.panel.emc_magnifier_time.y",                 "-1"                            },
+  { "game.panel.emc_magnifier_time.align",             "left"                          },
+  { "game.panel.emc_magnifier_time.valign",            "top"                           },
+  { "game.panel.emc_magnifier_time.digits",            "-1"                            },
+  { "game.panel.emc_magnifier_time.font",              "font.text_2"                   },
+  { "game.panel.emc_magnifier_time.draw_masked",       "true"                          },
+  { "game.panel.emc_magnifier_time.draw_order",                "0"                             },
+  { "game.panel.emc_magnifier_time.class",             "none"                          },
+  { "game.panel.emc_magnifier_time.style",             "none"                          },
+
+  { "game.panel.balloon_switch.x",                     "-1"                            },
+  { "game.panel.balloon_switch.y",                     "-1"                            },
+  { "game.panel.balloon_switch.tile_size",             "16"                            },
+  { "game.panel.balloon_switch.draw_masked",           "false"                         },
+  { "game.panel.balloon_switch.draw_order",            "0"                             },
+  { "game.panel.balloon_switch.class",                 "none"                          },
+  { "game.panel.balloon_switch.style",                 "none"                          },
+
+  { "game.panel.dynabomb_number.x",                    "-1"                            },
+  { "game.panel.dynabomb_number.y",                    "-1"                            },
+  { "game.panel.dynabomb_number.align",                        "left"                          },
+  { "game.panel.dynabomb_number.valign",               "top"                           },
+  { "game.panel.dynabomb_number.digits",               "-1"                            },
+  { "game.panel.dynabomb_number.font",                 "font.text_2"                   },
+  { "game.panel.dynabomb_number.draw_masked",          "true"                          },
+  { "game.panel.dynabomb_number.draw_order",           "0"                             },
+  { "game.panel.dynabomb_number.class",                        "none"                          },
+  { "game.panel.dynabomb_number.style",                        "none"                          },
+  { "game.panel.dynabomb_size.x",                      "-1"                            },
+  { "game.panel.dynabomb_size.y",                      "-1"                            },
+  { "game.panel.dynabomb_size.align",                  "left"                          },
+  { "game.panel.dynabomb_size.valign",                 "top"                           },
+  { "game.panel.dynabomb_size.digits",                 "-1"                            },
+  { "game.panel.dynabomb_size.font",                   "font.text_2"                   },
+  { "game.panel.dynabomb_size.draw_masked",            "true"                          },
+  { "game.panel.dynabomb_size.draw_order",             "0"                             },
+  { "game.panel.dynabomb_size.class",                  "none"                          },
+  { "game.panel.dynabomb_size.style",                  "none"                          },
+  { "game.panel.dynabomb_power.x",                     "-1"                            },
+  { "game.panel.dynabomb_power.y",                     "-1"                            },
+  { "game.panel.dynabomb_power.tile_size",             "16"                            },
+  { "game.panel.dynabomb_power.draw_masked",           "false"                         },
+  { "game.panel.dynabomb_power.draw_order",            "0"                             },
+  { "game.panel.dynabomb_power.class",                 "none"                          },
+  { "game.panel.dynabomb_power.style",                 "none"                          },
+
+  { "game.panel.penguins.x",                           "-1"                            },
+  { "game.panel.penguins.y",                           "-1"                            },
+  { "game.panel.penguins.align",                       "left"                          },
+  { "game.panel.penguins.valign",                      "top"                           },
+  { "game.panel.penguins.digits",                      "-1"                            },
+  { "game.panel.penguins.font",                                "font.text_2"                   },
+  { "game.panel.penguins.draw_masked",                 "true"                          },
+  { "game.panel.penguins.draw_order",                  "0"                             },
+  { "game.panel.penguins.class",                       "none"                          },
+  { "game.panel.penguins.style",                       "none"                          },
+
+  { "game.panel.sokoban_objects.x",                    "-1"                            },
+  { "game.panel.sokoban_objects.y",                    "-1"                            },
+  { "game.panel.sokoban_objects.align",                        "left"                          },
+  { "game.panel.sokoban_objects.valign",               "top"                           },
+  { "game.panel.sokoban_objects.digits",               "-1"                            },
+  { "game.panel.sokoban_objects.font",                 "font.text_2"                   },
+  { "game.panel.sokoban_objects.draw_masked",          "true"                          },
+  { "game.panel.sokoban_objects.draw_order",           "0"                             },
+  { "game.panel.sokoban_objects.class",                        "none"                          },
+  { "game.panel.sokoban_objects.style",                        "none"                          },
+  { "game.panel.sokoban_fields.x",                     "-1"                            },
+  { "game.panel.sokoban_fields.y",                     "-1"                            },
+  { "game.panel.sokoban_fields.align",                 "left"                          },
+  { "game.panel.sokoban_fields.valign",                        "top"                           },
+  { "game.panel.sokoban_fields.digits",                        "-1"                            },
+  { "game.panel.sokoban_fields.font",                  "font.text_2"                   },
+  { "game.panel.sokoban_fields.draw_masked",           "true"                          },
+  { "game.panel.sokoban_fields.draw_order",            "0"                             },
+  { "game.panel.sokoban_fields.class",                 "none"                          },
+  { "game.panel.sokoban_fields.style",                 "none"                          },
+
+  { "game.panel.robot_wheel.x",                                "-1"                            },
+  { "game.panel.robot_wheel.y",                                "-1"                            },
+  { "game.panel.robot_wheel.tile_size",                        "16"                            },
+  { "game.panel.robot_wheel.draw_masked",              "false"                         },
+  { "game.panel.robot_wheel.draw_order",               "0"                             },
+  { "game.panel.robot_wheel.class",                    "none"                          },
+  { "game.panel.robot_wheel.style",                    "none"                          },
+
+  { "game.panel.conveyor_belt_1.x",                    "-1"                            },
+  { "game.panel.conveyor_belt_1.y",                    "-1"                            },
+  { "game.panel.conveyor_belt_1.tile_size",            "16"                            },
+  { "game.panel.conveyor_belt_1.draw_masked",          "false"                         },
+  { "game.panel.conveyor_belt_1.draw_order",           "0"                             },
+  { "game.panel.conveyor_belt_1.class",                        "none"                          },
+  { "game.panel.conveyor_belt_1.style",                        "none"                          },
+  { "game.panel.conveyor_belt_1_switch.x",             "-1"                            },
+  { "game.panel.conveyor_belt_1_switch.y",             "-1"                            },
+  { "game.panel.conveyor_belt_1_switch.tile_size",     "16"                            },
+  { "game.panel.conveyor_belt_1_switch.draw_masked",   "false"                         },
+  { "game.panel.conveyor_belt_1_switch.draw_order",    "0"                             },
+  { "game.panel.conveyor_belt_1_switch.class",         "none"                          },
+  { "game.panel.conveyor_belt_1_switch.style",         "none"                          },
+  { "game.panel.conveyor_belt_2.x",                    "-1"                            },
+  { "game.panel.conveyor_belt_2.y",                    "-1"                            },
+  { "game.panel.conveyor_belt_2.tile_size",            "16"                            },
+  { "game.panel.conveyor_belt_2.draw_masked",          "false"                         },
+  { "game.panel.conveyor_belt_2.draw_order",           "0"                             },
+  { "game.panel.conveyor_belt_2.class",                        "none"                          },
+  { "game.panel.conveyor_belt_2.style",                        "none"                          },
+  { "game.panel.conveyor_belt_2_switch.x",             "-1"                            },
+  { "game.panel.conveyor_belt_2_switch.y",             "-1"                            },
+  { "game.panel.conveyor_belt_2_switch.tile_size",     "16"                            },
+  { "game.panel.conveyor_belt_2_switch.draw_masked",   "false"                         },
+  { "game.panel.conveyor_belt_2_switch.draw_order",    "0"                             },
+  { "game.panel.conveyor_belt_2_switch.class",         "none"                          },
+  { "game.panel.conveyor_belt_2_switch.style",         "none"                          },
+  { "game.panel.conveyor_belt_3.x",                    "-1"                            },
+  { "game.panel.conveyor_belt_3.y",                    "-1"                            },
+  { "game.panel.conveyor_belt_3.tile_size",            "16"                            },
+  { "game.panel.conveyor_belt_3.draw_masked",          "false"                         },
+  { "game.panel.conveyor_belt_3.draw_order",           "0"                             },
+  { "game.panel.conveyor_belt_3.class",                        "none"                          },
+  { "game.panel.conveyor_belt_3.style",                        "none"                          },
+  { "game.panel.conveyor_belt_3_switch.x",             "-1"                            },
+  { "game.panel.conveyor_belt_3_switch.y",             "-1"                            },
+  { "game.panel.conveyor_belt_3_switch.tile_size",     "16"                            },
+  { "game.panel.conveyor_belt_3_switch.draw_masked",   "false"                         },
+  { "game.panel.conveyor_belt_3_switch.draw_order",    "0"                             },
+  { "game.panel.conveyor_belt_3_switch.class",         "none"                          },
+  { "game.panel.conveyor_belt_3_switch.style",         "none"                          },
+  { "game.panel.conveyor_belt_4.x",                    "-1"                            },
+  { "game.panel.conveyor_belt_4.y",                    "-1"                            },
+  { "game.panel.conveyor_belt_4.tile_size",            "16"                            },
+  { "game.panel.conveyor_belt_4.draw_masked",          "false"                         },
+  { "game.panel.conveyor_belt_4.draw_order",           "0"                             },
+  { "game.panel.conveyor_belt_4.class",                        "none"                          },
+  { "game.panel.conveyor_belt_4.style",                        "none"                          },
+  { "game.panel.conveyor_belt_4_switch.x",             "-1"                            },
+  { "game.panel.conveyor_belt_4_switch.y",             "-1"                            },
+  { "game.panel.conveyor_belt_4_switch.tile_size",     "16"                            },
+  { "game.panel.conveyor_belt_4_switch.draw_masked",   "false"                         },
+  { "game.panel.conveyor_belt_4_switch.draw_order",    "0"                             },
+  { "game.panel.conveyor_belt_4_switch.class",         "none"                          },
+  { "game.panel.conveyor_belt_4_switch.style",         "none"                          },
+
+  { "game.panel.magic_wall.x",                         "-1"                            },
+  { "game.panel.magic_wall.y",                         "-1"                            },
+  { "game.panel.magic_wall.tile_size",                 "16"                            },
+  { "game.panel.magic_wall.draw_masked",               "false"                         },
+  { "game.panel.magic_wall.draw_order",                        "0"                             },
+  { "game.panel.magic_wall.class",                     "none"                          },
+  { "game.panel.magic_wall.style",                     "none"                          },
+  { "game.panel.magic_wall_time.x",                    "-1"                            },
+  { "game.panel.magic_wall_time.y",                    "-1"                            },
+  { "game.panel.magic_wall_time.align",                        "left"                          },
+  { "game.panel.magic_wall_time.valign",               "top"                           },
+  { "game.panel.magic_wall_time.digits",               "-1"                            },
+  { "game.panel.magic_wall_time.font",                 "font.text_2"                   },
+  { "game.panel.magic_wall_time.draw_masked",          "true"                          },
+  { "game.panel.magic_wall_time.draw_order",           "0"                             },
+  { "game.panel.magic_wall_time.class",                        "none"                          },
+  { "game.panel.magic_wall_time.style",                        "none"                          },
+
+  { "game.panel.gravity_state.x",                      "-1"                            },
+  { "game.panel.gravity_state.y",                      "-1"                            },
+  { "game.panel.gravity_state.align",                  "left"                          },
+  { "game.panel.gravity_state.valign",                 "top"                           },
+  { "game.panel.gravity_state.chars",                  "-1"                            },
+  { "game.panel.gravity_state.font",                   "font.text_1"                   },
+  { "game.panel.gravity_state.font_active",            "font.text_2"                   },
+  { "game.panel.gravity_state.draw_masked",            "true"                          },
+  { "game.panel.gravity_state.draw_order",             "0"                             },
+  { "game.panel.gravity_state.class",                  "none"                          },
+  { "game.panel.gravity_state.style",                  "none"                          },
+
+  { "game.panel.graphic_1.x",                          "-1"                            },
+  { "game.panel.graphic_1.y",                          "-1"                            },
+  { "game.panel.graphic_1.draw_masked",                        "true"                          },
+  { "game.panel.graphic_1.draw_order",                 "0"                             },
+  { "game.panel.graphic_1.class",                      "none"                          },
+  { "game.panel.graphic_1.style",                      "none"                          },
+  { "game.panel.graphic_2.x",                          "-1"                            },
+  { "game.panel.graphic_2.y",                          "-1"                            },
+  { "game.panel.graphic_2.draw_masked",                        "true"                          },
+  { "game.panel.graphic_2.draw_order",                 "0"                             },
+  { "game.panel.graphic_2.class",                      "none"                          },
+  { "game.panel.graphic_2.style",                      "none"                          },
+  { "game.panel.graphic_3.x",                          "-1"                            },
+  { "game.panel.graphic_3.y",                          "-1"                            },
+  { "game.panel.graphic_3.draw_masked",                        "true"                          },
+  { "game.panel.graphic_3.draw_order",                 "0"                             },
+  { "game.panel.graphic_3.class",                      "none"                          },
+  { "game.panel.graphic_3.style",                      "none"                          },
+  { "game.panel.graphic_4.x",                          "-1"                            },
+  { "game.panel.graphic_4.y",                          "-1"                            },
+  { "game.panel.graphic_4.draw_masked",                        "true"                          },
+  { "game.panel.graphic_4.draw_order",                 "0"                             },
+  { "game.panel.graphic_4.class",                      "none"                          },
+  { "game.panel.graphic_4.style",                      "none"                          },
+  { "game.panel.graphic_5.x",                          "-1"                            },
+  { "game.panel.graphic_5.y",                          "-1"                            },
+  { "game.panel.graphic_5.draw_masked",                        "true"                          },
+  { "game.panel.graphic_5.draw_order",                 "0"                             },
+  { "game.panel.graphic_5.class",                      "none"                          },
+  { "game.panel.graphic_5.style",                      "none"                          },
+  { "game.panel.graphic_6.x",                          "-1"                            },
+  { "game.panel.graphic_6.y",                          "-1"                            },
+  { "game.panel.graphic_6.draw_masked",                        "true"                          },
+  { "game.panel.graphic_6.draw_order",                 "0"                             },
+  { "game.panel.graphic_6.class",                      "none"                          },
+  { "game.panel.graphic_6.style",                      "none"                          },
+  { "game.panel.graphic_7.x",                          "-1"                            },
+  { "game.panel.graphic_7.y",                          "-1"                            },
+  { "game.panel.graphic_7.draw_masked",                        "true"                          },
+  { "game.panel.graphic_7.draw_order",                 "0"                             },
+  { "game.panel.graphic_7.class",                      "none"                          },
+  { "game.panel.graphic_7.style",                      "none"                          },
+  { "game.panel.graphic_8.x",                          "-1"                            },
+  { "game.panel.graphic_8.y",                          "-1"                            },
+  { "game.panel.graphic_8.draw_masked",                        "true"                          },
+  { "game.panel.graphic_8.draw_order",                 "0"                             },
+  { "game.panel.graphic_8.class",                      "none"                          },
+  { "game.panel.graphic_8.style",                      "none"                          },
+
+  { "game.panel.element_1.x",                          "-1"                            },
+  { "game.panel.element_1.y",                          "-1"                            },
+  { "game.panel.element_1.tile_size",                  "16"                            },
+  { "game.panel.element_1.element",                    "empty_space"                   },
+  { "game.panel.element_1.draw_masked",                        "false"                         },
+  { "game.panel.element_1.draw_order",                 "0"                             },
+  { "game.panel.element_1.class",                      "none"                          },
+  { "game.panel.element_1.style",                      "none"                          },
+  { "game.panel.element_1_count.x",                    "-1"                            },
+  { "game.panel.element_1_count.y",                    "-1"                            },
+  { "game.panel.element_1_count.align",                        "left"                          },
+  { "game.panel.element_1_count.valign",               "top"                           },
+  { "game.panel.element_1_count.digits",               "-1"                            },
+  { "game.panel.element_1_count.font",                 "font.text_2"                   },
+  { "game.panel.element_1_count.element",              "empty_space"                   },
+  { "game.panel.element_1_count.draw_masked",          "true"                          },
+  { "game.panel.element_1_count.draw_order",           "0"                             },
+  { "game.panel.element_1_count.class",                        "none"                          },
+  { "game.panel.element_1_count.style",                        "none"                          },
+  { "game.panel.element_2.x",                          "-1"                            },
+  { "game.panel.element_2.y",                          "-1"                            },
+  { "game.panel.element_2.tile_size",                  "16"                            },
+  { "game.panel.element_2.element",                    "empty_space"                   },
+  { "game.panel.element_2.draw_masked",                        "false"                         },
+  { "game.panel.element_2.draw_order",                 "0"                             },
+  { "game.panel.element_2.class",                      "none"                          },
+  { "game.panel.element_2.style",                      "none"                          },
+  { "game.panel.element_2_count.x",                    "-1"                            },
+  { "game.panel.element_2_count.y",                    "-1"                            },
+  { "game.panel.element_2_count.align",                        "left"                          },
+  { "game.panel.element_2_count.valign",               "top"                           },
+  { "game.panel.element_2_count.digits",               "-1"                            },
+  { "game.panel.element_2_count.font",                 "font.text_2"                   },
+  { "game.panel.element_2_count.element",              "empty_space"                   },
+  { "game.panel.element_2_count.draw_masked",          "true"                          },
+  { "game.panel.element_2_count.draw_order",           "0"                             },
+  { "game.panel.element_2_count.class",                        "none"                          },
+  { "game.panel.element_2_count.style",                        "none"                          },
+  { "game.panel.element_3.x",                          "-1"                            },
+  { "game.panel.element_3.y",                          "-1"                            },
+  { "game.panel.element_3.tile_size",                  "16"                            },
+  { "game.panel.element_3.element",                    "empty_space"                   },
+  { "game.panel.element_3.draw_masked",                        "false"                         },
+  { "game.panel.element_3.draw_order",                 "0"                             },
+  { "game.panel.element_3.class",                      "none"                          },
+  { "game.panel.element_3.style",                      "none"                          },
+  { "game.panel.element_3_count.x",                    "-1"                            },
+  { "game.panel.element_3_count.y",                    "-1"                            },
+  { "game.panel.element_3_count.align",                        "left"                          },
+  { "game.panel.element_3_count.valign",               "top"                           },
+  { "game.panel.element_3_count.digits",               "-1"                            },
+  { "game.panel.element_3_count.font",                 "font.text_2"                   },
+  { "game.panel.element_3_count.element",              "empty_space"                   },
+  { "game.panel.element_3_count.draw_masked",          "true"                          },
+  { "game.panel.element_3_count.draw_order",           "0"                             },
+  { "game.panel.element_3_count.class",                        "none"                          },
+  { "game.panel.element_3_count.style",                        "none"                          },
+  { "game.panel.element_4.x",                          "-1"                            },
+  { "game.panel.element_4.y",                          "-1"                            },
+  { "game.panel.element_4.tile_size",                  "16"                            },
+  { "game.panel.element_4.element",                    "empty_space"                   },
+  { "game.panel.element_4.draw_masked",                        "false"                         },
+  { "game.panel.element_4.draw_order",                 "0"                             },
+  { "game.panel.element_4.class",                      "none"                          },
+  { "game.panel.element_4.style",                      "none"                          },
+  { "game.panel.element_4_count.x",                    "-1"                            },
+  { "game.panel.element_4_count.y",                    "-1"                            },
+  { "game.panel.element_4_count.align",                        "left"                          },
+  { "game.panel.element_4_count.valign",               "top"                           },
+  { "game.panel.element_4_count.digits",               "-1"                            },
+  { "game.panel.element_4_count.font",                 "font.text_2"                   },
+  { "game.panel.element_4_count.element",              "empty_space"                   },
+  { "game.panel.element_4_count.draw_masked",          "true"                          },
+  { "game.panel.element_4_count.draw_order",           "0"                             },
+  { "game.panel.element_4_count.class",                        "none"                          },
+  { "game.panel.element_4_count.style",                        "none"                          },
+  { "game.panel.element_5.x",                          "-1"                            },
+  { "game.panel.element_5.y",                          "-1"                            },
+  { "game.panel.element_5.tile_size",                  "16"                            },
+  { "game.panel.element_5.element",                    "empty_space"                   },
+  { "game.panel.element_5.draw_masked",                        "false"                         },
+  { "game.panel.element_5.draw_order",                 "0"                             },
+  { "game.panel.element_5.class",                      "none"                          },
+  { "game.panel.element_5.style",                      "none"                          },
+  { "game.panel.element_5_count.x",                    "-1"                            },
+  { "game.panel.element_5_count.y",                    "-1"                            },
+  { "game.panel.element_5_count.align",                        "left"                          },
+  { "game.panel.element_5_count.valign",               "top"                           },
+  { "game.panel.element_5_count.digits",               "-1"                            },
+  { "game.panel.element_5_count.font",                 "font.text_2"                   },
+  { "game.panel.element_5_count.element",              "empty_space"                   },
+  { "game.panel.element_5_count.draw_masked",          "true"                          },
+  { "game.panel.element_5_count.draw_order",           "0"                             },
+  { "game.panel.element_5_count.class",                        "none"                          },
+  { "game.panel.element_5_count.style",                        "none"                          },
+  { "game.panel.element_6.x",                          "-1"                            },
+  { "game.panel.element_6.y",                          "-1"                            },
+  { "game.panel.element_6.tile_size",                  "16"                            },
+  { "game.panel.element_6.element",                    "empty_space"                   },
+  { "game.panel.element_6.draw_masked",                        "false"                         },
+  { "game.panel.element_6.draw_order",                 "0"                             },
+  { "game.panel.element_6.class",                      "none"                          },
+  { "game.panel.element_6.style",                      "none"                          },
+  { "game.panel.element_6_count.x",                    "-1"                            },
+  { "game.panel.element_6_count.y",                    "-1"                            },
+  { "game.panel.element_6_count.align",                        "left"                          },
+  { "game.panel.element_6_count.valign",               "top"                           },
+  { "game.panel.element_6_count.digits",               "-1"                            },
+  { "game.panel.element_6_count.font",                 "font.text_2"                   },
+  { "game.panel.element_6_count.element",              "empty_space"                   },
+  { "game.panel.element_6_count.draw_masked",          "true"                          },
+  { "game.panel.element_6_count.draw_order",           "0"                             },
+  { "game.panel.element_6_count.class",                        "none"                          },
+  { "game.panel.element_6_count.style",                        "none"                          },
+  { "game.panel.element_7.x",                          "-1"                            },
+  { "game.panel.element_7.y",                          "-1"                            },
+  { "game.panel.element_7.tile_size",                  "16"                            },
+  { "game.panel.element_7.element",                    "empty_space"                   },
+  { "game.panel.element_7.draw_masked",                        "false"                         },
+  { "game.panel.element_7.draw_order",                 "0"                             },
+  { "game.panel.element_7.class",                      "none"                          },
+  { "game.panel.element_7.style",                      "none"                          },
+  { "game.panel.element_7_count.x",                    "-1"                            },
+  { "game.panel.element_7_count.y",                    "-1"                            },
+  { "game.panel.element_7_count.align",                        "left"                          },
+  { "game.panel.element_7_count.valign",               "top"                           },
+  { "game.panel.element_7_count.digits",               "-1"                            },
+  { "game.panel.element_7_count.font",                 "font.text_2"                   },
+  { "game.panel.element_7_count.element",              "empty_space"                   },
+  { "game.panel.element_7_count.draw_masked",          "true"                          },
+  { "game.panel.element_7_count.draw_order",           "0"                             },
+  { "game.panel.element_7_count.class",                        "none"                          },
+  { "game.panel.element_7_count.style",                        "none"                          },
+  { "game.panel.element_8.x",                          "-1"                            },
+  { "game.panel.element_8.y",                          "-1"                            },
+  { "game.panel.element_8.tile_size",                  "16"                            },
+  { "game.panel.element_8.element",                    "empty_space"                   },
+  { "game.panel.element_8.draw_masked",                        "false"                         },
+  { "game.panel.element_8.draw_order",                 "0"                             },
+  { "game.panel.element_8.class",                      "none"                          },
+  { "game.panel.element_8.style",                      "none"                          },
+  { "game.panel.element_8_count.x",                    "-1"                            },
+  { "game.panel.element_8_count.y",                    "-1"                            },
+  { "game.panel.element_8_count.align",                        "left"                          },
+  { "game.panel.element_8_count.valign",               "top"                           },
+  { "game.panel.element_8_count.digits",               "-1"                            },
+  { "game.panel.element_8_count.font",                 "font.text_2"                   },
+  { "game.panel.element_8_count.element",              "empty_space"                   },
+  { "game.panel.element_8_count.draw_masked",          "true"                          },
+  { "game.panel.element_8_count.draw_order",           "0"                             },
+  { "game.panel.element_8_count.class",                        "none"                          },
+  { "game.panel.element_8_count.style",                        "none"                          },
+
+  { "game.panel.ce_score_1.x",                         "-1"                            },
+  { "game.panel.ce_score_1.y",                         "-1"                            },
+  { "game.panel.ce_score_1.align",                     "left"                          },
+  { "game.panel.ce_score_1.valign",                    "top"                           },
+  { "game.panel.ce_score_1.digits",                    "-1"                            },
+  { "game.panel.ce_score_1.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_1.element",                   "empty_space"                   },
+  { "game.panel.ce_score_1.draw_masked",               "true"                          },
+  { "game.panel.ce_score_1.draw_order",                        "0"                             },
+  { "game.panel.ce_score_1.class",                     "none"                          },
+  { "game.panel.ce_score_1.style",                     "none"                          },
+  { "game.panel.ce_score_1_element.x",                 "-1"                            },
+  { "game.panel.ce_score_1_element.y",                 "-1"                            },
+  { "game.panel.ce_score_1_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_1_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_1_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_1_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_1_element.class",             "none"                          },
+  { "game.panel.ce_score_1_element.style",             "none"                          },
+  { "game.panel.ce_score_2.x",                         "-1"                            },
+  { "game.panel.ce_score_2.y",                         "-1"                            },
+  { "game.panel.ce_score_2.align",                     "left"                          },
+  { "game.panel.ce_score_2.valign",                    "top"                           },
+  { "game.panel.ce_score_2.digits",                    "-1"                            },
+  { "game.panel.ce_score_2.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_2.element",                   "empty_space"                   },
+  { "game.panel.ce_score_2.draw_masked",               "true"                          },
+  { "game.panel.ce_score_2.draw_order",                        "0"                             },
+  { "game.panel.ce_score_2.class",                     "none"                          },
+  { "game.panel.ce_score_2.style",                     "none"                          },
+  { "game.panel.ce_score_2_element.x",                 "-1"                            },
+  { "game.panel.ce_score_2_element.y",                 "-1"                            },
+  { "game.panel.ce_score_2_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_2_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_2_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_2_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_2_element.class",             "none"                          },
+  { "game.panel.ce_score_2_element.style",             "none"                          },
+  { "game.panel.ce_score_3.x",                         "-1"                            },
+  { "game.panel.ce_score_3.y",                         "-1"                            },
+  { "game.panel.ce_score_3.align",                     "left"                          },
+  { "game.panel.ce_score_3.valign",                    "top"                           },
+  { "game.panel.ce_score_3.digits",                    "-1"                            },
+  { "game.panel.ce_score_3.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_3.element",                   "empty_space"                   },
+  { "game.panel.ce_score_3.draw_masked",               "true"                          },
+  { "game.panel.ce_score_3.draw_order",                        "0"                             },
+  { "game.panel.ce_score_3.class",                     "none"                          },
+  { "game.panel.ce_score_3.style",                     "none"                          },
+  { "game.panel.ce_score_3_element.x",                 "-1"                            },
+  { "game.panel.ce_score_3_element.y",                 "-1"                            },
+  { "game.panel.ce_score_3_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_3_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_3_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_3_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_3_element.class",             "none"                          },
+  { "game.panel.ce_score_3_element.style",             "none"                          },
+  { "game.panel.ce_score_4.x",                         "-1"                            },
+  { "game.panel.ce_score_4.y",                         "-1"                            },
+  { "game.panel.ce_score_4.align",                     "left"                          },
+  { "game.panel.ce_score_4.valign",                    "top"                           },
+  { "game.panel.ce_score_4.digits",                    "-1"                            },
+  { "game.panel.ce_score_4.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_4.element",                   "empty_space"                   },
+  { "game.panel.ce_score_4.draw_masked",               "true"                          },
+  { "game.panel.ce_score_4.draw_order",                        "0"                             },
+  { "game.panel.ce_score_4.class",                     "none"                          },
+  { "game.panel.ce_score_4.style",                     "none"                          },
+  { "game.panel.ce_score_4_element.x",                 "-1"                            },
+  { "game.panel.ce_score_4_element.y",                 "-1"                            },
+  { "game.panel.ce_score_4_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_4_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_4_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_4_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_4_element.class",             "none"                          },
+  { "game.panel.ce_score_4_element.style",             "none"                          },
+  { "game.panel.ce_score_5.x",                         "-1"                            },
+  { "game.panel.ce_score_5.y",                         "-1"                            },
+  { "game.panel.ce_score_5.align",                     "left"                          },
+  { "game.panel.ce_score_5.valign",                    "top"                           },
+  { "game.panel.ce_score_5.digits",                    "-1"                            },
+  { "game.panel.ce_score_5.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_5.element",                   "empty_space"                   },
+  { "game.panel.ce_score_5.draw_masked",               "true"                          },
+  { "game.panel.ce_score_5.draw_order",                        "0"                             },
+  { "game.panel.ce_score_5.class",                     "none"                          },
+  { "game.panel.ce_score_5.style",                     "none"                          },
+  { "game.panel.ce_score_5_element.x",                 "-1"                            },
+  { "game.panel.ce_score_5_element.y",                 "-1"                            },
+  { "game.panel.ce_score_5_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_5_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_5_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_5_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_5_element.class",             "none"                          },
+  { "game.panel.ce_score_5_element.style",             "none"                          },
+  { "game.panel.ce_score_6.x",                         "-1"                            },
+  { "game.panel.ce_score_6.y",                         "-1"                            },
+  { "game.panel.ce_score_6.align",                     "left"                          },
+  { "game.panel.ce_score_6.valign",                    "top"                           },
+  { "game.panel.ce_score_6.digits",                    "-1"                            },
+  { "game.panel.ce_score_6.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_6.element",                   "empty_space"                   },
+  { "game.panel.ce_score_6.draw_masked",               "true"                          },
+  { "game.panel.ce_score_6.draw_order",                        "0"                             },
+  { "game.panel.ce_score_6.class",                     "none"                          },
+  { "game.panel.ce_score_6.style",                     "none"                          },
+  { "game.panel.ce_score_6_element.x",                 "-1"                            },
+  { "game.panel.ce_score_6_element.y",                 "-1"                            },
+  { "game.panel.ce_score_6_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_6_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_6_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_6_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_6_element.class",             "none"                          },
+  { "game.panel.ce_score_6_element.style",             "none"                          },
+  { "game.panel.ce_score_7.x",                         "-1"                            },
+  { "game.panel.ce_score_7.y",                         "-1"                            },
+  { "game.panel.ce_score_7.align",                     "left"                          },
+  { "game.panel.ce_score_7.valign",                    "top"                           },
+  { "game.panel.ce_score_7.digits",                    "-1"                            },
+  { "game.panel.ce_score_7.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_7.element",                   "empty_space"                   },
+  { "game.panel.ce_score_7.draw_masked",               "true"                          },
+  { "game.panel.ce_score_7.draw_order",                        "0"                             },
+  { "game.panel.ce_score_7.class",                     "none"                          },
+  { "game.panel.ce_score_7.style",                     "none"                          },
+  { "game.panel.ce_score_7_element.x",                 "-1"                            },
+  { "game.panel.ce_score_7_element.y",                 "-1"                            },
+  { "game.panel.ce_score_7_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_7_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_7_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_7_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_7_element.class",             "none"                          },
+  { "game.panel.ce_score_7_element.style",             "none"                          },
+  { "game.panel.ce_score_8.x",                         "-1"                            },
+  { "game.panel.ce_score_8.y",                         "-1"                            },
+  { "game.panel.ce_score_8.align",                     "left"                          },
+  { "game.panel.ce_score_8.valign",                    "top"                           },
+  { "game.panel.ce_score_8.digits",                    "-1"                            },
+  { "game.panel.ce_score_8.font",                      "font.text_2"                   },
+  { "game.panel.ce_score_8.element",                   "empty_space"                   },
+  { "game.panel.ce_score_8.draw_masked",               "true"                          },
+  { "game.panel.ce_score_8.draw_order",                        "0"                             },
+  { "game.panel.ce_score_8.class",                     "none"                          },
+  { "game.panel.ce_score_8.style",                     "none"                          },
+  { "game.panel.ce_score_8_element.x",                 "-1"                            },
+  { "game.panel.ce_score_8_element.y",                 "-1"                            },
+  { "game.panel.ce_score_8_element.tile_size",         "16"                            },
+  { "game.panel.ce_score_8_element.element",           "empty_space"                   },
+  { "game.panel.ce_score_8_element.draw_masked",       "false"                         },
+  { "game.panel.ce_score_8_element.draw_order",                "0"                             },
+  { "game.panel.ce_score_8_element.class",             "none"                          },
+  { "game.panel.ce_score_8_element.style",             "none"                          },
+
+  { "game.panel.player_name.x",                                "-1"                            },
+  { "game.panel.player_name.y",                                "-1"                            },
+  { "game.panel.player_name.align",                    "left"                          },
+  { "game.panel.player_name.valign",                   "top"                           },
+  { "game.panel.player_name.chars",                    "-1"                            },
+  { "game.panel.player_name.font",                     "font.text_2"                   },
+  { "game.panel.player_name.draw_masked",              "true"                          },
+  { "game.panel.player_name.draw_order",               "0"                             },
+  { "game.panel.player_name.class",                    "none"                          },
+  { "game.panel.player_name.style",                    "none"                          },
+
+  { "game.panel.level_name.x",                         "-1"                            },
+  { "game.panel.level_name.y",                         "-1"                            },
+  { "game.panel.level_name.align",                     "left"                          },
+  { "game.panel.level_name.valign",                    "top"                           },
+  { "game.panel.level_name.chars",                     "-1"                            },
+  { "game.panel.level_name.font",                      "font.text_2"                   },
+  { "game.panel.level_name.draw_masked",               "true"                          },
+  { "game.panel.level_name.draw_order",                        "0"                             },
+  { "game.panel.level_name.class",                     "none"                          },
+  { "game.panel.level_name.style",                     "none"                          },
+  { "game.panel.level_author.x",                       "-1"                            },
+  { "game.panel.level_author.y",                       "-1"                            },
+  { "game.panel.level_author.align",                   "left"                          },
+  { "game.panel.level_author.valign",                  "top"                           },
+  { "game.panel.level_author.chars",                   "-1"                            },
+  { "game.panel.level_author.font",                    "font.text_2"                   },
+  { "game.panel.level_author.draw_masked",             "true"                          },
+  { "game.panel.level_author.draw_order",              "0"                             },
+  { "game.panel.level_author.class",                   "none"                          },
+  { "game.panel.level_author.style",                   "none"                          },
+
+  { "game.button.stop.x",                              "5"                             },
+  { "game.button.stop.y",                              "215"                           },
+  { "game.button.pause.x",                             "35"                            },
+  { "game.button.pause.y",                             "215"                           },
+  { "game.button.play.x",                              "65"                            },
+  { "game.button.play.y",                              "215"                           },
+  { "game.button.undo.x",                              "-1"                            },
+  { "game.button.undo.y",                              "-1"                            },
+  { "game.button.redo.x",                              "-1"                            },
+  { "game.button.redo.y",                              "-1"                            },
+  { "game.button.save.x",                              "-1"                            },
+  { "game.button.save.y",                              "-1"                            },
+  { "game.button.pause2.x",                            "-1"                            },
+  { "game.button.pause2.y",                            "-1"                            },
+  { "game.button.load.x",                              "-1"                            },
+  { "game.button.load.y",                              "-1"                            },
+  { "game.button.restart.x",                           "-1"                            },
+  { "game.button.restart.y",                           "-1"                            },
+  { "game.button.sound_music.x",                       "5"                             },
+  { "game.button.sound_music.y",                       "245"                           },
+  { "game.button.sound_loops.x",                       "35"                            },
+  { "game.button.sound_loops.y",                       "245"                           },
+  { "game.button.sound_simple.x",                      "65"                            },
+  { "game.button.sound_simple.y",                      "245"                           },
+
+  { "game.button.panel_stop.x",                                "-1"                            },
+  { "game.button.panel_stop.y",                                "-1"                            },
+  { "game.button.panel_pause.x",                       "-1"                            },
+  { "game.button.panel_pause.y",                       "-1"                            },
+  { "game.button.panel_play.x",                                "-1"                            },
+  { "game.button.panel_play.y",                                "-1"                            },
+  { "game.button.panel_restart.x",                     "-1"                            },
+  { "game.button.panel_restart.y",                     "-1"                            },
+  { "game.button.panel_sound_music.x",                 "-1"                            },
+  { "game.button.panel_sound_music.y",                 "-1"                            },
+  { "game.button.panel_sound_loops.x",                 "-1"                            },
+  { "game.button.panel_sound_loops.y",                 "-1"                            },
+  { "game.button.panel_sound_simple.x",                        "-1"                            },
+  { "game.button.panel_sound_simple.y",                        "-1"                            },
+
+  { "game.button.touch_stop.x",                                "0"                             },
+  { "game.button.touch_stop.y",                                "0"                             },
+  { "game.button.touch_pause.x",                       "-60"                           },
+  { "game.button.touch_pause.y",                       "0"                             },
+  { "game.button.touch_restart.x",                     "-1"                            },
+  { "game.button.touch_restart.y",                     "-1"                            },
+
+  { "tape.button.eject.x",                             "5"                             },
+  { "tape.button.eject.y",                             "77"                            },
+  { "tape.button.stop.x",                              "23"                            },
+  { "tape.button.stop.y",                              "77"                            },
+  { "tape.button.pause.x",                             "41"                            },
+  { "tape.button.pause.y",                             "77"                            },
+  { "tape.button.record.x",                            "59"                            },
+  { "tape.button.record.y",                            "77"                            },
+  { "tape.button.play.x",                              "77"                            },
+  { "tape.button.play.y",                              "77"                            },
+
+  { "tape.button.insert_solution.x",                   "-1"                            },
+  { "tape.button.insert_solution.y",                   "-1"                            },
+  { "tape.button.play_solution.x",                     "-1"                            },
+  { "tape.button.play_solution.y",                     "-1"                            },
+
+  { "tape.symbol.eject.x",                             "-1"                            },
+  { "tape.symbol.eject.y",                             "-1"                            },
+  { "tape.symbol.stop.x",                              "-1"                            },
+  { "tape.symbol.stop.y",                              "-1"                            },
+  { "tape.symbol.pause.x",                             "40"                            },
+  { "tape.symbol.pause.y",                             "41"                            },
+  { "tape.symbol.record.x",                            "25"                            },
+  { "tape.symbol.record.y",                            "41"                            },
+  { "tape.symbol.play.x",                              "57"                            },
+  { "tape.symbol.play.y",                              "41"                            },
+  { "tape.symbol.fast_forward.x",                      "39"                            },
+  { "tape.symbol.fast_forward.y",                      "42"                            },
+  { "tape.symbol.warp_forward.x",                      "39"                            },
+  { "tape.symbol.warp_forward.y",                      "42"                            },
+  { "tape.symbol.warp_forward_blind.x",                        "39"                            },
+  { "tape.symbol.warp_forward_blind.y",                        "42"                            },
+  { "tape.symbol.pause_before_end.x",                  "-1"                            },
+  { "tape.symbol.pause_before_end.y",                  "-1"                            },
+  { "tape.symbol.single_step.x",                       "-1"                            },
+  { "tape.symbol.single_step.y",                       "-1"                            },
+
+  { "tape.label.eject.x",                              "-1"                            },
+  { "tape.label.eject.y",                              "-1"                            },
+  { "tape.label.stop.x",                               "-1"                            },
+  { "tape.label.stop.y",                               "-1"                            },
+  { "tape.label.pause.x",                              "5"                             },
+  { "tape.label.pause.y",                              "61"                            },
+  { "tape.label.record.x",                             "5"                             },
+  { "tape.label.record.y",                             "41"                            },
+  { "tape.label.play.x",                               "70"                            },
+  { "tape.label.play.y",                               "41"                            },
+  { "tape.label.fast_forward.x",                       "5"                             },
+  { "tape.label.fast_forward.y",                       "42"                            },
+  { "tape.label.warp_forward.x",                       "5"                             },
+  { "tape.label.warp_forward.y",                       "42"                            },
+  { "tape.label.warp_forward_blind.x",                 "5"                             },
+  { "tape.label.warp_forward_blind.y",                 "42"                            },
+  { "tape.label.pause_before_end.x",                   "5"                             },
+  { "tape.label.pause_before_end.y",                   "42"                            },
+  { "tape.label.single_step.x",                                "57"                            },
+  { "tape.label.single_step.y",                                "42"                            },
+
+  { "tape.label.date.x",                               "5"                             },
+  { "tape.label.date.y",                               "5"                             },
+  { "tape.label.time.x",                               "46"                            },
+  { "tape.label.time.y",                               "55"                            },
+
+  { "tape.text.date.x",                                        "7"                             },
+  { "tape.text.date.y",                                        "19"                            },
+  { "tape.text.date.align",                            "left"                          },
+  { "tape.text.date.valign",                           "top"                           },
+  { "tape.text.date.digits",                           "-1"                            },
+  { "tape.text.date.xoffset",                          "27"                            },
+  { "tape.text.date.2nd_xoffset",                      "64"                            },
+  { "tape.text.date.font",                             "font.tape_recorder"            },
+  { "tape.text.date.draw_masked",                      "false"                         },
+
+  { "tape.text.date_yyyy.x",                           "-1"                            },
+  { "tape.text.date_yyyy.y",                           "-1"                            },
+  { "tape.text.date_yyyy.align",                       "left"                          },
+  { "tape.text.date_yyyy.valign",                      "top"                           },
+  { "tape.text.date_yyyy.digits",                      "4"                             },
+  { "tape.text.date_yyyy.font",                                "font.tape_recorder"            },
+  { "tape.text.date_yyyy.draw_masked",                 "false"                         },
+  { "tape.text.date_yy.x",                             "-1"                            },
+  { "tape.text.date_yy.y",                             "-1"                            },
+  { "tape.text.date_yy.align",                         "left"                          },
+  { "tape.text.date_yy.valign",                                "top"                           },
+  { "tape.text.date_yy.digits",                                "2"                             },
+  { "tape.text.date_yy.font",                          "font.tape_recorder"            },
+  { "tape.text.date_yy.draw_masked",                   "false"                         },
+  { "tape.text.date_mon.x",                            "-1"                            },
+  { "tape.text.date_mon.y",                            "-1"                            },
+  { "tape.text.date_mon.align",                                "left"                          },
+  { "tape.text.date_mon.valign",                       "top"                           },
+  { "tape.text.date_mon.chars",                                "3"                             },
+  { "tape.text.date_mon.font",                         "font.tape_recorder"            },
+  { "tape.text.date_mon.draw_masked",                  "false"                         },
+  { "tape.text.date_mm.x",                             "-1"                            },
+  { "tape.text.date_mm.y",                             "-1"                            },
+  { "tape.text.date_mm.align",                         "left"                          },
+  { "tape.text.date_mm.valign",                                "top"                           },
+  { "tape.text.date_mm.digits",                                "2"                             },
+  { "tape.text.date_mm.font",                          "font.tape_recorder"            },
+  { "tape.text.date_mm.draw_masked",                   "false"                         },
+  { "tape.text.date_dd.x",                             "-1"                            },
+  { "tape.text.date_dd.y",                             "-1"                            },
+  { "tape.text.date_dd.align",                         "left"                          },
+  { "tape.text.date_dd.valign",                                "top"                           },
+  { "tape.text.date_dd.digits",                                "2"                             },
+  { "tape.text.date_dd.font",                          "font.tape_recorder"            },
+  { "tape.text.date_dd.draw_masked",                   "false"                         },
+
+  { "tape.text.time.x",                                        "44"                            },
+  { "tape.text.time.y",                                        "55"                            },
+  { "tape.text.time.align",                            "left"                          },
+  { "tape.text.time.valign",                           "top"                           },
+  { "tape.text.time.digits",                           "-1"                            },
+  { "tape.text.time.xoffset",                          "27"                            },
+  { "tape.text.time.font",                             "font.tape_recorder"            },
+  { "tape.text.time.draw_masked",                      "false"                         },
+
+  { "tape.text.time_hh.x",                             "-1"                            },
+  { "tape.text.time_hh.y",                             "-1"                            },
+  { "tape.text.time_hh.align",                         "left"                          },
+  { "tape.text.time_hh.valign",                                "top"                           },
+  { "tape.text.time_hh.digits",                                "2"                             },
+  { "tape.text.time_hh.font",                          "font.tape_recorder"            },
+  { "tape.text.time_hh.draw_masked",                   "false"                         },
+  { "tape.text.time_mm.x",                             "-1"                            },
+  { "tape.text.time_mm.y",                             "-1"                            },
+  { "tape.text.time_mm.align",                         "left"                          },
+  { "tape.text.time_mm.valign",                                "top"                           },
+  { "tape.text.time_mm.digits",                                "2"                             },
+  { "tape.text.time_mm.font",                          "font.tape_recorder"            },
+  { "tape.text.time_mm.draw_masked",                   "false"                         },
+  { "tape.text.time_ss.x",                             "-1"                            },
+  { "tape.text.time_ss.y",                             "-1"                            },
+  { "tape.text.time_ss.align",                         "left"                          },
+  { "tape.text.time_ss.valign",                                "top"                           },
+  { "tape.text.time_ss.digits",                                "2"                             },
+  { "tape.text.time_ss.font",                          "font.tape_recorder"            },
+  { "tape.text.time_ss.draw_masked",                   "false"                         },
+
+  { "tape.text.frame.x",                               "-1"                            },
+  { "tape.text.frame.y",                               "-1"                            },
+  { "tape.text.frame.align",                           "left"                          },
+  { "tape.text.frame.valign",                          "top"                           },
+  { "tape.text.frame.digits",                          "-1"                            },
+  { "tape.text.frame.font",                            "font.tape_recorder"            },
+  { "tape.text.frame.draw_masked",                     "false"                         },
+
+  { "tape.show_game_buttons",                          "false"                         },
+
+  { "editor.button.prev_level.x",                      "5"                             },
+  { "editor.button.prev_level.y",                      "5"                             },
+  { "editor.button.next_level.x",                      "79"                            },
+  { "editor.button.next_level.y",                      "5"                             },
+
+  { "editor.button.properties.x",                      "5"                             },
+  { "editor.button.properties.y",                      "230"                           },
+
+  { "editor.button.element_left.x",                    "-1"                            },
+  { "editor.button.element_left.y",                    "-1"                            },
+  { "editor.button.element_left.tile_size",            "-1"                            },
+  { "editor.button.element_middle.x",                  "-1"                            },
+  { "editor.button.element_middle.y",                  "-1"                            },
+  { "editor.button.element_middle.tile_size",          "-1"                            },
+  { "editor.button.element_right.x",                   "-1"                            },
+  { "editor.button.element_right.y",                   "-1"                            },
+  { "editor.button.element_right.tile_size",           "-1"                            },
+
+  { "editor.button.palette.x",                         "-1"                            },
+  { "editor.button.palette.y",                         "-1"                            },
+
+  { "editor.button.draw_single.x",                     "6"                             },
+  { "editor.button.draw_single.y",                     "6"                             },
+  { "editor.button.draw_connected.x",                  "28"                            },
+  { "editor.button.draw_connected.y",                  "6"                             },
+  { "editor.button.draw_line.x",                       "50"                            },
+  { "editor.button.draw_line.y",                       "6"                             },
+  { "editor.button.draw_arc.x",                                "72"                            },
+  { "editor.button.draw_arc.y",                                "6"                             },
+  { "editor.button.draw_rectangle.x",                  "6"                             },
+  { "editor.button.draw_rectangle.y",                  "28"                            },
+  { "editor.button.draw_filled_box.x",                 "28"                            },
+  { "editor.button.draw_filled_box.y",                 "28"                            },
+  { "editor.button.rotate_up.x",                       "50"                            },
+  { "editor.button.rotate_up.y",                       "28"                            },
+  { "editor.button.draw_text.x",                       "72"                            },
+  { "editor.button.draw_text.y",                       "28"                            },
+  { "editor.button.flood_fill.x",                      "6"                             },
+  { "editor.button.flood_fill.y",                      "50"                            },
+  { "editor.button.rotate_left.x",                     "28"                            },
+  { "editor.button.rotate_left.y",                     "50"                            },
+  { "editor.button.zoom_level.x",                      "50"                            },
+  { "editor.button.zoom_level.y",                      "50"                            },
+  { "editor.button.rotate_right.x",                    "72"                            },
+  { "editor.button.rotate_right.y",                    "50"                            },
+  { "editor.button.draw_random.x",                     "6"                             },
+  { "editor.button.draw_random.y",                     "72"                            },
+  { "editor.button.grab_brush.x",                      "28"                            },
+  { "editor.button.grab_brush.y",                      "72"                            },
+  { "editor.button.rotate_down.x",                     "50"                            },
+  { "editor.button.rotate_down.y",                     "72"                            },
+  { "editor.button.pick_element.x",                    "72"                            },
+  { "editor.button.pick_element.y",                    "72"                            },
+
+  { "editor.button.ce_copy_from.x",                    "28"                            },
+  { "editor.button.ce_copy_from.y",                    "6"                             },
+  { "editor.button.ce_copy_to.x",                      "50"                            },
+  { "editor.button.ce_copy_to.y",                      "6"                             },
+  { "editor.button.ce_swap.x",                         "72"                            },
+  { "editor.button.ce_swap.y",                         "6"                             },
+  { "editor.button.ce_copy.x",                         "6"                             },
+  { "editor.button.ce_copy.y",                         "72"                            },
+  { "editor.button.ce_paste.x",                                "28"                            },
+  { "editor.button.ce_paste.y",                                "72"                            },
+
+  { "editor.button.undo.x",                            "5"                             },
+  { "editor.button.undo.y",                            "99"                            },
+  { "editor.button.conf.x",                            "35"                            },
+  { "editor.button.conf.y",                            "99"                            },
+  { "editor.button.save.x",                            "65"                            },
+  { "editor.button.save.y",                            "99"                            },
+  { "editor.button.clear.x",                           "5"                             },
+  { "editor.button.clear.y",                           "119"                           },
+  { "editor.button.test.x",                            "35"                            },
+  { "editor.button.test.y",                            "119"                           },
+  { "editor.button.exit.x",                            "65"                            },
+  { "editor.button.exit.y",                            "119"                           },
+
+  { "editor.input.level_number.x",                     "29"                            },
+  { "editor.input.level_number.y",                     "5"                             },
+
+  { "editor.palette.x",                                        "5"                             },
+  { "editor.palette.y",                                        "30"                            },
+  { "editor.palette.cols",                             "4"                             },
+  { "editor.palette.rows",                             "10"                            },
+  { "editor.palette.tile_size",                                "16"                            },
+  { "editor.palette.show_as_separate_screen",          "false"                         },
+  { "editor.palette.show_on_element_buttons",          "false"                         },
+
+  { "editor.palette.element_left.x",                   "6"                             },
+  { "editor.palette.element_left.y",                   "258"                           },
+  { "editor.palette.element_left.tile_size",           "16"                            },
+  { "editor.palette.element_middle.x",                 "42"                            },
+  { "editor.palette.element_middle.y",                 "258"                           },
+  { "editor.palette.element_middle.tile_size",         "16"                            },
+  { "editor.palette.element_right.x",                  "78"                            },
+  { "editor.palette.element_right.y",                  "258"                           },
+  { "editor.palette.element_right.tile_size",          "16"                            },
+
+  { "editor.drawingarea.tile_size",                    "16"                            },
+
+  { "editor.settings.headline.x",                      "272"                           },
+  { "editor.settings.headline.y",                      "16"                            },
+  { "editor.settings.headline.align",                  "center"                        },
+  { "editor.settings.element_graphic.x",               "24"                            },
+  { "editor.settings.element_graphic.y",               "64"                            },
+  { "editor.settings.element_name.x",                  "-1"                            },
+  { "editor.settings.element_name.y",                  "-1"                            },
+  { "editor.settings.tabs.x",                          "24"                            },
+  { "editor.settings.tabs.y",                          "64"                            },
+  { "editor.settings.tabs.2nd_yoffset",                        "64"                            },
+  { "editor.settings.tabs.draw_xoffset",               "0"                             },
+  { "editor.settings.tabs.draw_yoffset",               "8"                             },
+  { "editor.settings.tooltip.x",                       "-1"                            },
+  { "editor.settings.tooltip.y",                       "-1"                            },
+
+  { "editor.gadget.normal_spacing",                    "4"                             },
+  { "editor.gadget.small_spacing",                     "2"                             },
+  { "editor.gadget.tiny_spacing",                      "1"                             },
+  { "editor.gadget.line_spacing",                      "4"                             },
+  { "editor.gadget.text_spacing",                      "4"                             },
+  { "editor.gadget.separator_line.height",             "2"                             },
+
+  { "request.button.yes.x",                            "2"                             },
+  { "request.button.yes.y",                            "250"                           },
+  { "request.button.no.x",                             "52"                            },
+  { "request.button.no.y",                             "250"                           },
+  { "request.button.confirm.x",                                "2"                             },
+  { "request.button.confirm.y",                                "250"                           },
+  { "request.button.player_1.x",                       "35"                            },
+  { "request.button.player_1.y",                       "185"                           },
+  { "request.button.player_1.draw_player",             "true"                          },
+  { "request.button.player_1.tile_size",               "16"                            },
+  { "request.button.player_2.x",                       "65"                            },
+  { "request.button.player_2.y",                       "215"                           },
+  { "request.button.player_2.draw_player",             "true"                          },
+  { "request.button.player_2.tile_size",               "16"                            },
+  { "request.button.player_3.x",                       "35"                            },
+  { "request.button.player_3.y",                       "245"                           },
+  { "request.button.player_3.draw_player",             "true"                          },
+  { "request.button.player_3.tile_size",               "16"                            },
+  { "request.button.player_4.x",                       "5"                             },
+  { "request.button.player_4.y",                       "215"                           },
+  { "request.button.player_4.draw_player",             "true"                          },
+  { "request.button.player_4.tile_size",               "16"                            },
+
+  { "request.button.touch_yes.x",                      "0"                             },
+  { "request.button.touch_yes.y",                      "-56"                           },
+  { "request.button.touch_no.x",                       "-92"                           },
+  { "request.button.touch_no.y",                       "-56"                           },
+  { "request.button.touch_confirm.x",                  "0"                             },
+  { "request.button.touch_confirm.y",                  "-56"                           },
+
+  { "request.x",                                       "-1"                            },
+  { "request.y",                                       "-1"                            },
+  { "request.width",                                   "120"                           },
+  { "request.height",                                  "300"                           },
+  { "request.border_size",                             "10"                            },
+  { "request.line_spacing",                            "2"                             },
+  { "request.step_offset",                             "10"                            },
+  { "request.step_delay",                              "20"                            },
+  { "request.anim_mode",                               "default"                       },
+  { "request.align",                                   "center"                        },
+  { "request.valign",                                  "middle"                        },
+  { "request.autowrap",                                        "false"                         },
+  { "request.centered",                                        "true"                          },
+  { "request.wrap_single_words",                       "true"                          },
+  { "request.draw_order",                              "-1"                            },
+
+  { "global.use_envelope_request",                     "false"                         },
+
+  { "game.graphics_engine_version",                    "-1"                            },
+  { "game.forced_scroll_delay_value",                  "-1"                            },
+  { "game.forced_scroll_x",                            ARG_UNDEFINED                   },
+  { "game.forced_scroll_y",                            ARG_UNDEFINED                   },
+  { "game.use_native_bd_graphics_engine",              "false"                         },
+  { "game.use_native_emc_graphics_engine",             "false"                         },
+  { "game.use_native_sp_graphics_engine",              "true"                          },
+  { "game.use_masked_pushing",                         "false"                         },
+  { "game.use_masked_elements",                                "false"                         },
+  { "game.tile_size",                                  "32"                            },
+
+  { "[player].boring_delay_fixed",                     "1000"                          },
+  { "[player].boring_delay_random",                    "1000"                          },
+  { "[player].sleeping_delay_fixed",                   "2000"                          },
+  { "[player].sleeping_delay_random",                  "2000"                          },
+
+  { "viewport.window.width",                           "672"                           },
+  { "viewport.window.height",                          "560"                           },
+  { "viewport.window.min_width",                       "-1"                            },
+  { "viewport.window.min_height",                      "-1"                            },
+  { "viewport.window.max_width",                       "-1"                            },
+  { "viewport.window.max_height",                      "-1"                            },
+  { "viewport.window.TITLE.width",                     ARG_DEFAULT                     },
+  { "viewport.window.TITLE.height",                    ARG_DEFAULT                     },
+
+  { "viewport.playfield.x",                            "6"                             },
+  { "viewport.playfield.y",                            "6"                             },
+  { "viewport.playfield.width",                                "548"                           },
+  { "viewport.playfield.height",                       "548"                           },
+  { "viewport.playfield.min_width",                    "-1"                            },
+  { "viewport.playfield.min_height",                   "-1"                            },
+  { "viewport.playfield.max_width",                    "-1"                            },
+  { "viewport.playfield.max_height",                   "-1"                            },
+  { "viewport.playfield.margin_left",                  "0"                             },
+  { "viewport.playfield.margin_right",                 "0"                             },
+  { "viewport.playfield.margin_top",                   "0"                             },
+  { "viewport.playfield.margin_bottom",                        "0"                             },
+  { "viewport.playfield.border_left",                  "-1"                            },
+  { "viewport.playfield.border_right",                 "-1"                            },
+  { "viewport.playfield.border_top",                   "-1"                            },
+  { "viewport.playfield.border_bottom",                        "-1"                            },
+  { "viewport.playfield.border_size",                  "2"                             },
+  { "viewport.playfield.align_size",                   "16"                            },
+  { "viewport.playfield.align",                                "left"                          },
+  { "viewport.playfield.valign",                       "top"                           },
+  { "viewport.playfield.MAIN.x",                       ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.y",                       ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.width",                   ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.height",                  ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.min_width",               ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.min_height",              ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.max_width",               ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.max_height",              ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.margin_left",             ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.margin_right",            ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.margin_top",              ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.margin_bottom",           ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.border_left",             ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.border_right",            ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.border_top",              ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.border_bottom",           ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.border_size",             ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.align_size",              ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.align",                   ARG_DEFAULT                     },
+  { "viewport.playfield.MAIN.valign",                  ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.x",                     ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.y",                     ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.width",                 ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.height",                        ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.min_width",             ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.min_height",            ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.max_width",             ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.max_height",            ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.margin_left",           ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.margin_right",          ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.margin_top",            ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.margin_bottom",         ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.border_left",           ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.border_right",          ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.border_top",            ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.border_bottom",         ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.border_size",           ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.align_size",            ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.align",                 ARG_DEFAULT                     },
+  { "viewport.playfield.SCORES.valign",                        ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.x",                     ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.y",                     ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.width",                 ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.height",                        ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.min_width",             ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.min_height",            ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.max_width",             ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.max_height",            ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.margin_left",           ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.margin_right",          ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.margin_top",            ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.margin_bottom",         ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.border_left",           ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.border_right",          ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.border_top",            ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.border_bottom",         ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.border_size",           ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.align_size",            ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.align",                 ARG_DEFAULT                     },
+  { "viewport.playfield.EDITOR.valign",                        ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.x",                    ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.y",                    ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.width",                        ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.height",               ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.min_width",            ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.min_height",           ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.max_width",            ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.max_height",           ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.margin_left",          ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.margin_right",         ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.margin_top",           ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.margin_bottom",                ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.border_left",          ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.border_right",         ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.border_top",           ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.border_bottom",                ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.border_size",          ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.align_size",           ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.align",                        ARG_DEFAULT                     },
+  { "viewport.playfield.PLAYING.valign",               ARG_DEFAULT                     },
+
+  { "viewport.door_1.x",                               "566"                           },
+  { "viewport.door_1.y",                               "60"                            },
+  { "viewport.door_1.width",                           "100"                           },
+  { "viewport.door_1.height",                          "280"                           },
+  { "viewport.door_1.border_size",                     "4"                             },
+  { "viewport.door_1.align",                           "left"                          },
+  { "viewport.door_1.valign",                          "top"                           },
+  { "viewport.door_1.MAIN.x",                          ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.y",                          ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.width",                      ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.height",                     ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.border_size",                        ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.align",                      ARG_DEFAULT                     },
+  { "viewport.door_1.MAIN.valign",                     ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.x",                                ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.y",                                ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.width",                    ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.height",                   ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.border_size",              ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.align",                    ARG_DEFAULT                     },
+  { "viewport.door_1.SCORES.valign",                   ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.x",                                ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.y",                                ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.width",                    ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.height",                   ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.border_size",              ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.align",                    ARG_DEFAULT                     },
+  { "viewport.door_1.EDITOR.valign",                   ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.x",                       ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.y",                       ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.width",                   ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.height",                  ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.border_size",             ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.align",                   ARG_DEFAULT                     },
+  { "viewport.door_1.PLAYING.valign",                  ARG_DEFAULT                     },
+
+  { "viewport.door_2.x",                               "566"                           },
+  { "viewport.door_2.y",                               "400"                           },
+  { "viewport.door_2.width",                           "100"                           },
+  { "viewport.door_2.height",                          "100"                           },
+  { "viewport.door_2.border_size",                     "4"                             },
+  { "viewport.door_2.align",                           "left"                          },
+  { "viewport.door_2.valign",                          "top"                           },
+  { "viewport.door_2.MAIN.x",                          ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.y",                          ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.width",                      ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.height",                     ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.border_size",                        ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.align",                      ARG_DEFAULT                     },
+  { "viewport.door_2.MAIN.valign",                     ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.x",                                ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.y",                                ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.width",                    ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.height",                   ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.border_size",              ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.align",                    ARG_DEFAULT                     },
+  { "viewport.door_2.SCORES.valign",                   ARG_DEFAULT                     },
+  { "viewport.door_2.EDITOR.x",                                "566"                           },
+  { "viewport.door_2.EDITOR.y",                                "356"                           },
+  { "viewport.door_2.EDITOR.width",                    "100"                           },
+  { "viewport.door_2.EDITOR.height",                   "144"                           },
+  { "viewport.door_2.EDITOR.border_size",              "4"                             },
+  { "viewport.door_2.EDITOR.align",                    "left"                          },
+  { "viewport.door_2.EDITOR.valign",                   "top"                           },
+  { "viewport.door_2.PLAYING.x",                       ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.y",                       ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.width",                   ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.height",                  ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.border_size",             ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.align",                   ARG_DEFAULT                     },
+  { "viewport.door_2.PLAYING.valign",                  ARG_DEFAULT                     },
+
+  { NULL,                                              NULL                            }
 };
index d11a5bff1b4a402e5a7f9e545547fbbcaadac3b3..0df8a79bf21f547d6aa7656f9d5524aca7ae57c5 100644 (file)
 
 struct ConfigTypeInfo music_config_suffix[] =
 {
-  { ".mode_loop",                      ARG_UNDEFINED,  TYPE_BOOLEAN    },
+  { ".mode_loop",                              ARG_UNDEFINED,  TYPE_BOOLEAN    },
 
-  { NULL,                              NULL,           0               }
+  { NULL,                                      NULL,           0               }
 };
 
 struct ConfigInfo music_config[] =
 {
-  { "background",                      UNDEFINED_FILENAME              },
-  { "background.TITLE_INITIAL",                UNDEFINED_FILENAME              },
-  { "background.TITLE",                        UNDEFINED_FILENAME              },
-  { "background.MAIN",                 UNDEFINED_FILENAME              },
-  { "background.NAMES",                        UNDEFINED_FILENAME              },
-  { "background.LEVELS",               UNDEFINED_FILENAME              },
-  { "background.LEVELNR",              UNDEFINED_FILENAME              },
-  { "background.SCORES",               UNDEFINED_FILENAME              },
-  { "background.EDITOR",               UNDEFINED_FILENAME              },
-  { "background.INFO",                 "rhythmloop.wav"                },
-  { "background.SETUP",                        UNDEFINED_FILENAME              },
+  { "background",                              UNDEFINED_FILENAME              },
+  { "background.TITLE_INITIAL",                        UNDEFINED_FILENAME              },
+  { "background.TITLE",                                UNDEFINED_FILENAME              },
+  { "background.MAIN",                         UNDEFINED_FILENAME              },
+  { "background.NAMES",                                UNDEFINED_FILENAME              },
+  { "background.LEVELS",                       UNDEFINED_FILENAME              },
+  { "background.LEVELNR",                      UNDEFINED_FILENAME              },
+  { "background.SCORES",                       UNDEFINED_FILENAME              },
+  { "background.EDITOR",                       UNDEFINED_FILENAME              },
+  { "background.INFO",                         "rhythmloop.wav"                },
+  { "background.INFO[ELEMENTS]",               UNDEFINED_FILENAME              },
+  { "background.INFO[CREDITS]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[PROGRAM]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[VERSION]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[LEVELSET]",               UNDEFINED_FILENAME              },
+  { "background.SETUP",                                UNDEFINED_FILENAME              },
 
-  { "background.titlescreen_initial_1",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_2",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_3",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_4",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_5",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_1",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_2",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_3",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_4",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_5",                UNDEFINED_FILENAME              },
-  { "background.titlemessage_initial_1",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_2",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_3",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_4",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_5",UNDEFINED_FILENAME             },
-  { "background.titlemessage_1",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_2",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_3",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_4",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_5",       UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_1",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_2",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_3",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_4",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_5",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_1",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_2",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_3",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_4",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_5",                        UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_1",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_2",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_3",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_4",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_5",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_1",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_2",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_3",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_4",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_5",               UNDEFINED_FILENAME              },
 
   // there is no definition for "background.PLAYING", because this would
   // prevent selecting music from music directory that is not defined in
index eacaf778e52e2fff8bdc97946fdf0970fae12917..3b38b50d499c1f5c90cab10b98ce52fa415bc061 100644 (file)
 
 struct ConfigTypeInfo sound_config_suffix[] =
 {
-  { ".mode_loop",                      ARG_UNDEFINED,  TYPE_BOOLEAN    },
-  { ".volume",                         "100",          TYPE_INTEGER    },
-  { ".priority",                       "0",            TYPE_INTEGER    },
+  { ".mode_loop",                              ARG_UNDEFINED,  TYPE_BOOLEAN    },
+  { ".volume",                                 "100",          TYPE_INTEGER    },
+  { ".priority",                               "0",            TYPE_INTEGER    },
 
-  { NULL,                              NULL,           0               }
+  { NULL,                                      NULL,           0               }
 };
 
 struct ConfigInfo sound_config[] =
 {
   // some default sounds
-  { "[default].digging",               "schlurf.wav"                   },
-  { "[default].collecting",            "pong.wav"                      },
-  { "[default].snapping",              "pong.wav"                      },
-  { "[default].pushing",               "pusch.wav"                     },
-  { "[default].impact",                        "klopf.wav"                     },
-  { "[default].walking",               "empty.wav"                     },
-  { "[default].passing",               "gate.wav"                      },
-  { "[default].dying",                 "autsch.wav"                    },
-  { "[default].exploding",             "roaaar.wav"                    },
-  { "[default].hitting",               "kink.wav"                      },
-  { "[sp_default].exploding",          "booom.wav"                     },
-  { "[mm_default].exploding",          "kabumm.wav"                    },
+  { "[default].digging",                       "schlurf.wav"                   },
+  { "[default].collecting",                    "pong.wav"                      },
+  { "[default].snapping",                      "pong.wav"                      },
+  { "[default].pushing",                       "pusch.wav"                     },
+  { "[default].impact",                                "klopf.wav"                     },
+  { "[default].walking",                       "empty.wav"                     },
+  { "[default].passing",                       "gate.wav"                      },
+  { "[default].dying",                         "autsch.wav"                    },
+  { "[default].exploding",                     "roaaar.wav"                    },
+  { "[default].hitting",                       "kink.wav"                      },
+  { "[sp_default].exploding",                  "booom.wav"                     },
+  { "[mm_default].exploding",                  "kabumm.wav"                    },
 
   // sounds for Boulder Dash style elements and actions
-  { "bd_diamond.collecting",           "pong.wav"                      },
-  { "bd_diamond.impact",               "pling.wav"                     },
-  { "bd_rock.pushing",                 "pusch.wav"                     },
-  { "bd_rock.impact",                  "klopf.wav"                     },
-  { "bd_magic_wall.activating",                "quirk.wav"                     },
-  { "bd_magic_wall.active",            "miep.wav"                      },
-  { "bd_magic_wall.filling",           "quirk.wav"                     },
-  { "bd_amoeba.waiting",               UNDEFINED_FILENAME              },
-  { "bd_amoeba.growing",               "amoebe.wav"                    },
-  { "bd_amoeba.turning_to_gem",                "pling.wav"                     },
-  { "bd_amoeba.turning_to_rock",       "klopf.wav"                     },
-  { "bd_butterfly.moving",             "klapper.wav"                   },
-  { "bd_butterfly.waiting",            "klapper.wav"                   },
-  { "bd_firefly.moving",               "roehr.wav"                     },
-  { "bd_firefly.waiting",              "roehr.wav"                     },
+  { "bd_diamond.collecting",                   "pong.wav"                      },
+  { "bd_diamond.falling",                      UNDEFINED_FILENAME              },
+  { "bd_diamond.impact",                       "pling.wav"                     },
+  { "bd_rock.pushing",                         "pusch.wav"                     },
+  { "bd_rock.falling",                         UNDEFINED_FILENAME              },
+  { "bd_rock.impact",                          "klopf.wav"                     },
+  { "bd_magic_wall.activating",                        "quirk.wav"                     },
+  { "bd_magic_wall.active",                    "miep.wav"                      },
+  { "bd_magic_wall.filling",                   "quirk.wav"                     },
+  { "bd_amoeba.waiting",                       UNDEFINED_FILENAME              },
+  { "bd_amoeba.growing",                       "amoebe.wav"                    },
+  { "bd_amoeba.turning_to_gem",                        "pling.wav"                     },
+  { "bd_amoeba.turning_to_gem.mode_loop",      "false"                         },
+  { "bd_amoeba.turning_to_rock",               "klopf.wav"                     },
+  { "bd_amoeba.turning_to_rock.mode_loop",     "false"                         },
+  { "bd_butterfly.moving",                     "klapper.wav"                   },
+  { "bd_butterfly.waiting",                    "klapper.wav"                   },
+  { "bd_firefly.moving",                       "roehr.wav"                     },
+  { "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.impact",                    "schlurf.wav"                   },
+  { "bdx_sand_loose.falling",                  UNDEFINED_FILENAME              },
+  { "bdx_sand_loose.impact",                   "schlurf.wav"                   },
+  { "bdx_diamond.collecting",                  "pong.wav"                      },
+  { "bdx_diamond.falling",                     UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact",                      "pling.wav"                     },
+  { "bdx_flying_diamond.collecting",           "pong.wav"                      },
+  { "bdx_flying_diamond.falling",              UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact",               "pling.wav"                     },
+  { "bdx_rock.pushing",                                "pusch.wav"                     },
+  { "bdx_rock.falling",                                UNDEFINED_FILENAME              },
+  { "bdx_rock.impact",                         "klopf.wav"                     },
+  { "bdx_flying_rock.pushing",                 "pusch.wav"                     },
+  { "bdx_flying_rock.falling",                 UNDEFINED_FILENAME              },
+  { "bdx_flying_rock.impact",                  "klopf.wav"                     },
+  { "bdx_mega_rock.pushing",                   "pusch.wav"                     },
+  { "bdx_mega_rock.falling",                   UNDEFINED_FILENAME              },
+  { "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.impact",                          "klumpf.wav"                    },
+  { "bdx_nitro_pack.pushing",                  "pusch.wav"                     },
+  { "bdx_nitro_pack.impact",                   "klopf.wav"                     },
+  { "bdx_bomb.collecting",                     "pong.wav"                      },
+  { "bdx_bomb.dropping",                       "zisch.wav"                     },
+  { "bdx_magic_wall.active",                   "miep.wav"                      },
+  { "bdx_amoeba_1.active",                     UNDEFINED_FILENAME              },
+  { "bdx_amoeba_1.other",                      UNDEFINED_FILENAME              },
+  { "bdx_amoeba_2.active",                     UNDEFINED_FILENAME              },
+  { "bdx_pneumatic_hammer.active",             "hammer.wav"                    },
+  { "bdx_covered.active",                      "jingle.wav"                    },
+  { "bdx_inbox.opening",                       "crash.wav"                     },
 
   // sounds for Supaplex style elements and actions
-  { "sp_base.digging",                 "base.wav"                      },
-  { "sp_buggy_base.digging",           "base.wav"                      },
-  { "sp_buggy_base.active",            "bug.wav"                       },
-  { "sp_infotron.collecting",          "infotron.wav"                  },
-  { "sp_infotron.impact",              "pling.wav"                     },
-  { "sp_zonk.pushing",                 "zonkpush.wav"                  },
-  { "sp_zonk.impact",                  "zonkdown.wav"                  },
-  { "sp_disk_red.collecting",          "infotron.wav"                  },
-  { "sp_disk_orange.pushing",          "zonkpush.wav"                  },
-  { "sp_disk_yellow.pushing",          "pusch.wav"                     },
-  { "[sp_port].passing",               "gate.wav"                      },
-  { "[sp_exit].passing",               "exit.wav"                      },
-  { "[sp_exit].opening",               UNDEFINED_FILENAME              },
-  { "[sp_exit].closing",               UNDEFINED_FILENAME              },
-  { "sp_sniksnak.moving",              UNDEFINED_FILENAME              },
-  { "sp_sniksnak.waiting",             UNDEFINED_FILENAME              },
-  { "sp_electron.moving",              UNDEFINED_FILENAME              },
-  { "sp_electron.waiting",             UNDEFINED_FILENAME              },
-  { "sp_terminal.activating",          UNDEFINED_FILENAME              },
-  { "sp_terminal.active",              UNDEFINED_FILENAME              },
+  { "sp_base.digging",                         "base.wav"                      },
+  { "sp_buggy_base.digging",                   "base.wav"                      },
+  { "sp_buggy_base.active",                    "bug.wav"                       },
+  { "sp_infotron.collecting",                  "infotron.wav"                  },
+  { "sp_infotron.impact",                      "pling.wav"                     },
+  { "sp_zonk.pushing",                         "zonkpush.wav"                  },
+  { "sp_zonk.impact",                          "zonkdown.wav"                  },
+  { "sp_disk_red.collecting",                  "infotron.wav"                  },
+  { "sp_disk_orange.pushing",                  "zonkpush.wav"                  },
+  { "sp_disk_yellow.pushing",                  "pusch.wav"                     },
+  { "[sp_port].passing",                       "gate.wav"                      },
+  { "[sp_exit].passing",                       "exit.wav"                      },
+  { "[sp_exit].opening",                       UNDEFINED_FILENAME              },
+  { "[sp_exit].closing",                       UNDEFINED_FILENAME              },
+  { "sp_sniksnak.moving",                      UNDEFINED_FILENAME              },
+  { "sp_sniksnak.waiting",                     UNDEFINED_FILENAME              },
+  { "sp_electron.moving",                      UNDEFINED_FILENAME              },
+  { "sp_electron.waiting",                     UNDEFINED_FILENAME              },
+  { "sp_terminal.activating",                  UNDEFINED_FILENAME              },
+  { "sp_terminal.active",                      UNDEFINED_FILENAME              },
 
   // sounds for Sokoban style elements and actions
-  { "[sokoban].pushing",               "pusch.wav"                     },
-  { "[sokoban].filling",               "deng.wav"                      },
-  { "[sokoban].emptying",              UNDEFINED_FILENAME              },
+  { "[sokoban].pushing",                       "pusch.wav"                     },
+  { "[sokoban].filling",                       "deng.wav"                      },
+  { "[sokoban].emptying",                      UNDEFINED_FILENAME              },
 
   // sounds for Emerald Mine style elements and actions
-  { "[player].moving",                 "empty.wav"                     },
-  { "[player].moving.mode_loop",       "false"                         },
-  { "sand.digging",                    "schlurf.wav"                   },
-  { "[emerald].collecting",            "pong.wav"                      },
-  { "[emerald].impact",                        "pling.wav"                     },
-  { "diamond.collecting",              "pong.wav"                      },
-  { "diamond.impact",                  "pling.wav"                     },
-  { "diamond.breaking",                        "quirk.wav"                     },
-  { "rock.pushing",                    "pusch.wav"                     },
-  { "rock.impact",                     "klopf.wav"                     },
-  { "bomb.pushing",                    "pusch.wav"                     },
-  { "nut.pushing",                     "knurk.wav"                     },
-  { "nut.breaking",                    "knack.wav"                     },
-  { "nut.impact",                      "klumpf.wav"                    },
-  { "[dynamite].collecting",           "pong.wav"                      },
-  { "[dynamite].dropping",             "deng.wav"                      },
-  { "[dynamite].active",               "zisch.wav"                     },
-  { "[key].collecting",                        "pong.wav"                      },
-  { "[gate].passing",                  "gate.wav"                      },
-  { "bug.moving",                      "klapper.wav"                   },
-  { "bug.waiting",                     "klapper.wav"                   },
-  { "spaceship.moving",                        "roehr.wav"                     },
-  { "spaceship.waiting",               "roehr.wav"                     },
-  { "yamyam.moving",                   UNDEFINED_FILENAME              },
-  { "yamyam.waiting",                  "njam.wav"                      },
-  { "yamyam.digging",                  "njam.wav"                      },
-  { "robot.moving",                    "schlurf.wav"                   },
-  { "robot.moving.mode_loop",          "false"                         },
-  { "robot.waiting",                   UNDEFINED_FILENAME              },
-  { "robot_wheel.activating",          "deng.wav"                      },
-  { "robot_wheel.active",              "miep.wav"                      },
-  { "magic_wall.activating",           "quirk.wav"                     },
-  { "magic_wall.active",               "miep.wav"                      },
-  { "magic_wall.filling",              "quirk.wav"                     },
-  { "dc_magic_wall.activating",                "quirk.wav"                     },
-  { "dc_magic_wall.active",            "miep.wav"                      },
-  { "dc_magic_wall.filling",           "quirk.wav"                     },
-  { "[amoeba].waiting",                        UNDEFINED_FILENAME              },
-  { "[amoeba].growing",                        "amoebe.wav"                    },
-  { "[amoeba].dropping",               UNDEFINED_FILENAME              },
-  { "acid.splashing",                  "blurb.wav"                     },
-  { "[quicksand].filling",             UNDEFINED_FILENAME              },
-  { "[quicksand].emptying",            UNDEFINED_FILENAME              },
-  { "[exit].opening",                  "oeffnen.wav"                   },
-  { "[exit].closing",                  "oeffnen.wav"                   },
-  { "[exit].passing",                  "buing.wav"                     },
-  { "[steel_exit].opening",            "oeffnen.wav"                   },
-  { "[steel_exit].closing",            "oeffnen.wav"                   },
-  { "[steel_exit].passing",            "buing.wav"                     },
-  { "[em_exit].opening",               "gong.wav"                      },
-  { "[em_exit].closing",               UNDEFINED_FILENAME              },
-  { "[em_exit].passing",               "buing.wav"                     },
-  { "[em_steel_exit].opening",         "gong.wav"                      },
-  { "[em_steel_exit].closing",         UNDEFINED_FILENAME              },
-  { "[em_steel_exit].passing",         "buing.wav"                     },
-  { "penguin.passing",                 "buing.wav"                     },
+  { "[player].moving",                         "empty.wav"                     },
+  { "[player].moving.mode_loop",               "false"                         },
+  { "sand.digging",                            "schlurf.wav"                   },
+  { "[emerald].collecting",                    "pong.wav"                      },
+  { "[emerald].impact",                                "pling.wav"                     },
+  { "diamond.collecting",                      "pong.wav"                      },
+  { "diamond.impact",                          "pling.wav"                     },
+  { "diamond.breaking",                                "quirk.wav"                     },
+  { "rock.pushing",                            "pusch.wav"                     },
+  { "rock.impact",                             "klopf.wav"                     },
+  { "bomb.pushing",                            "pusch.wav"                     },
+  { "nut.pushing",                             "knurk.wav"                     },
+  { "nut.breaking",                            "knack.wav"                     },
+  { "nut.impact",                              "klumpf.wav"                    },
+  { "[dynamite].collecting",                   "pong.wav"                      },
+  { "[dynamite].dropping",                     "deng.wav"                      },
+  { "[dynamite].active",                       "zisch.wav"                     },
+  { "[key].collecting",                                "pong.wav"                      },
+  { "[gate].passing",                          "gate.wav"                      },
+  { "bug.moving",                              "klapper.wav"                   },
+  { "bug.waiting",                             "klapper.wav"                   },
+  { "spaceship.moving",                                "roehr.wav"                     },
+  { "spaceship.waiting",                       "roehr.wav"                     },
+  { "yamyam.moving",                           UNDEFINED_FILENAME              },
+  { "yamyam.waiting",                          "njam.wav"                      },
+  { "yamyam.digging",                          "njam.wav"                      },
+  { "robot.moving",                            "schlurf.wav"                   },
+  { "robot.moving.mode_loop",                  "false"                         },
+  { "robot.waiting",                           UNDEFINED_FILENAME              },
+  { "robot_wheel.activating",                  "deng.wav"                      },
+  { "robot_wheel.active",                      "miep.wav"                      },
+  { "magic_wall.activating",                   "quirk.wav"                     },
+  { "magic_wall.active",                       "miep.wav"                      },
+  { "magic_wall.filling",                      "quirk.wav"                     },
+  { "dc_magic_wall.activating",                        "quirk.wav"                     },
+  { "dc_magic_wall.active",                    "miep.wav"                      },
+  { "dc_magic_wall.filling",                   "quirk.wav"                     },
+  { "[amoeba].waiting",                                UNDEFINED_FILENAME              },
+  { "[amoeba].growing",                                "amoebe.wav"                    },
+  { "[amoeba].dropping",                       UNDEFINED_FILENAME              },
+  { "acid.splashing",                          "blurb.wav"                     },
+  { "[quicksand].filling",                     UNDEFINED_FILENAME              },
+  { "[quicksand].emptying",                    UNDEFINED_FILENAME              },
+  { "[exit].opening",                          "oeffnen.wav"                   },
+  { "[exit].closing",                          "oeffnen.wav"                   },
+  { "[exit].passing",                          "buing.wav"                     },
+  { "[steel_exit].opening",                    "oeffnen.wav"                   },
+  { "[steel_exit].closing",                    "oeffnen.wav"                   },
+  { "[steel_exit].passing",                    "buing.wav"                     },
+  { "[em_exit].opening",                       "gong.wav"                      },
+  { "[em_exit].closing",                       UNDEFINED_FILENAME              },
+  { "[em_exit].passing",                       "buing.wav"                     },
+  { "[em_steel_exit].opening",                 "gong.wav"                      },
+  { "[em_steel_exit].closing",                 UNDEFINED_FILENAME              },
+  { "[em_steel_exit].passing",                 "buing.wav"                     },
+  { "penguin.passing",                         "buing.wav"                     },
 
   // sounds for Emerald Mine Club style elements and actions
-  { "balloon.moving",                  UNDEFINED_FILENAME              },
-  { "balloon.waiting",                 UNDEFINED_FILENAME              },
-  { "balloon.pushing",                 "schlurf.wav"                   },
-  { "[balloon_switch].activating",     UNDEFINED_FILENAME              },
-  { "spring.moving",                   UNDEFINED_FILENAME              },
-  { "spring.pushing",                  "pusch.wav"                     },
-  { "spring.impact",                   "klopf.wav"                     },
-  { "[wall].growing",                  UNDEFINED_FILENAME              },
-  { "emc_android.pushing",             "pusch.wav"                     },
-  { "emc_android.moving",              "roehr.wav"                     },
-  { "emc_android.moving.mode_loop",    "false"                         },
-  { "emc_android.dropping",            "deng.wav"                      },
-  { "emc_magic_ball.dropping",         "deng.wav"                      },
+  { "balloon.moving",                          UNDEFINED_FILENAME              },
+  { "balloon.waiting",                         UNDEFINED_FILENAME              },
+  { "balloon.pushing",                         "schlurf.wav"                   },
+  { "[balloon_switch].activating",             UNDEFINED_FILENAME              },
+  { "spring.moving",                           UNDEFINED_FILENAME              },
+  { "spring.pushing",                          "pusch.wav"                     },
+  { "spring.impact",                           "klopf.wav"                     },
+  { "[wall].growing",                          UNDEFINED_FILENAME              },
+  { "emc_android.pushing",                     "pusch.wav"                     },
+  { "emc_android.moving",                      "roehr.wav"                     },
+  { "emc_android.moving.mode_loop",            "false"                         },
+  { "emc_android.dropping",                    "deng.wav"                      },
+  { "emc_magic_ball.dropping",                 "deng.wav"                      },
 
   // sounds for Diamond Caves style elements and actions
-  { "pearl.collecting",                        "pong.wav"                      },
-  { "pearl.breaking",                  "knack.wav"                     },
-  { "pearl.impact",                    "pling.wav"                     },
-  { "crystal.collecting",              "pong.wav"                      },
-  { "crystal.impact",                  "pling.wav"                     },
-  { "[envelope].collecting",           "pong.wav"                      },
-  { "[envelope].opening",              UNDEFINED_FILENAME              },
-  { "[envelope].closing",              UNDEFINED_FILENAME              },
-  { "invisible_sand.digging",          "schlurf.wav"                   },
-  { "invisible_sand.active.digging",   "schlurf.wav"                   },
-  { "shield_normal.collecting",                "pong.wav"                      },
-  { "shield_normal.active",            UNDEFINED_FILENAME              },
-  { "shield_deadly.collecting",                "pong.wav"                      },
-  { "shield_deadly.active",            UNDEFINED_FILENAME              },
-  { "extra_time.collecting",           "gong.wav"                      },
-  { "mole.moving",                     UNDEFINED_FILENAME              },
-  { "mole.waiting",                    UNDEFINED_FILENAME              },
-  { "mole.digging",                    "blurb.wav"                     },
-  { "[switchgate_switch].activating",  UNDEFINED_FILENAME              },
-  { "[switchgate].opening",            "oeffnen.wav"                   },
-  { "[switchgate].closing",            "oeffnen.wav"                   },
-  { "[switchgate].passing",            "gate.wav"                      },
-  { "[timegate_switch].activating",    "deng.wav"                      },
-  { "[timegate_switch].active",                "miep.wav"                      },
-  { "[timegate_switch].deactivating",  UNDEFINED_FILENAME              },
-  { "[timegate].opening",              "oeffnen.wav"                   },
-  { "[timegate].closing",              "oeffnen.wav"                   },
-  { "[timegate].passing",              "gate.wav"                      },
-  { "[conveyor_belt_switch].activating",UNDEFINED_FILENAME             },
-  { "[conveyor_belt].active",          UNDEFINED_FILENAME              },
-  { "[conveyor_belt_switch].deactivating",UNDEFINED_FILENAME           },
-  { "light_switch.activating",         UNDEFINED_FILENAME              },
-  { "light_switch.deactivating",       UNDEFINED_FILENAME              },
+  { "pearl.collecting",                                "pong.wav"                      },
+  { "pearl.breaking",                          "knack.wav"                     },
+  { "pearl.impact",                            "pling.wav"                     },
+  { "crystal.collecting",                      "pong.wav"                      },
+  { "crystal.impact",                          "pling.wav"                     },
+  { "[envelope].collecting",                   "pong.wav"                      },
+  { "[envelope].opening",                      UNDEFINED_FILENAME              },
+  { "[envelope].closing",                      UNDEFINED_FILENAME              },
+  { "invisible_sand.digging",                  "schlurf.wav"                   },
+  { "invisible_sand.active.digging",           "schlurf.wav"                   },
+  { "shield_normal.collecting",                        "pong.wav"                      },
+  { "shield_normal.active",                    UNDEFINED_FILENAME              },
+  { "shield_deadly.collecting",                        "pong.wav"                      },
+  { "shield_deadly.active",                    UNDEFINED_FILENAME              },
+  { "extra_time.collecting",                   "gong.wav"                      },
+  { "mole.moving",                             UNDEFINED_FILENAME              },
+  { "mole.waiting",                            UNDEFINED_FILENAME              },
+  { "mole.digging",                            "blurb.wav"                     },
+  { "[switchgate_switch].activating",          UNDEFINED_FILENAME              },
+  { "[switchgate].opening",                    "oeffnen.wav"                   },
+  { "[switchgate].closing",                    "oeffnen.wav"                   },
+  { "[switchgate].passing",                    "gate.wav"                      },
+  { "[timegate_switch].activating",            "deng.wav"                      },
+  { "[timegate_switch].active",                        "miep.wav"                      },
+  { "[timegate_switch].deactivating",          UNDEFINED_FILENAME              },
+  { "[timegate].opening",                      "oeffnen.wav"                   },
+  { "[timegate].closing",                      "oeffnen.wav"                   },
+  { "[timegate].passing",                      "gate.wav"                      },
+  { "[conveyor_belt_switch].activating",       UNDEFINED_FILENAME              },
+  { "[conveyor_belt].active",                  UNDEFINED_FILENAME              },
+  { "[conveyor_belt_switch].deactivating",     UNDEFINED_FILENAME              },
+  { "light_switch.activating",                 UNDEFINED_FILENAME              },
+  { "light_switch.deactivating",               UNDEFINED_FILENAME              },
 
   // sounds for DX Boulderdash style elements and actions
-  { "dx_supabomb.pushing",             "pusch.wav"                     },
-  { "trap.digging",                    "schlurf.wav"                   },
-  { "trap.activating",                 UNDEFINED_FILENAME              },
-  { "[tube].walking",                  UNDEFINED_FILENAME              },
+  { "dx_supabomb.pushing",                     "pusch.wav"                     },
+  { "trap.digging",                            "schlurf.wav"                   },
+  { "trap.activating",                         UNDEFINED_FILENAME              },
+  { "[tube].walking",                          UNDEFINED_FILENAME              },
 
   // sounds for Rocks'n'Diamonds style elements and actions
-  { "amoeba.turning_to_gem",           "pling.wav"                     },
-  { "amoeba.turning_to_rock",          "klopf.wav"                     },
-  { "speed_pill.collecting",           "pong.wav"                      },
-  { "dynabomb_increase_number.collecting","pong.wav"                   },
-  { "dynabomb_increase_size.collecting","pong.wav"                     },
-  { "dynabomb_increase_power.collecting","pong.wav"                    },
-  { "[dynabomb].dropping",             "deng.wav"                      },
-  { "[dynabomb].active",               "zisch.wav"                     },
-  { "satellite.moving",                        UNDEFINED_FILENAME              },
-  { "satellite.waiting",               UNDEFINED_FILENAME              },
-  { "satellite.pushing",               "pusch.wav"                     },
-  { "lamp.activating",                 "deng.wav"                      },
-  { "lamp.deactivating",               "deng.wav"                      },
-  { "time_orb_full.collecting",                "gong.wav"                      },
-  { "time_orb_full.impact",            "deng.wav"                      },
-  { "time_orb_empty.pushing",          "pusch.wav"                     },
-  { "time_orb_empty.impact",           "deng.wav"                      },
-  { "game_of_life.waiting",            UNDEFINED_FILENAME              },
-  { "game_of_life.growing",            "amoebe.wav"                    },
-  { "biomaze.waiting",                 UNDEFINED_FILENAME              },
-  { "biomaze.growing",                 "amoebe.wav"                    },
-  { "pacman.moving",                   UNDEFINED_FILENAME              },
-  { "pacman.waiting",                  UNDEFINED_FILENAME              },
-  { "pacman.digging",                  UNDEFINED_FILENAME              },
-  { "dark_yamyam.moving",              UNDEFINED_FILENAME              },
-  { "dark_yamyam.waiting",             "njam.wav"                      },
-  { "dark_yamyam.digging",             UNDEFINED_FILENAME              },
-  { "penguin.moving",                  UNDEFINED_FILENAME              },
-  { "penguin.waiting",                 UNDEFINED_FILENAME              },
-  { "pig.moving",                      UNDEFINED_FILENAME              },
-  { "pig.waiting",                     UNDEFINED_FILENAME              },
-  { "pig.digging",                     UNDEFINED_FILENAME              },
-  { "dragon.moving",                   UNDEFINED_FILENAME              },
-  { "dragon.waiting",                  UNDEFINED_FILENAME              },
-  { "dragon.attacking",                        UNDEFINED_FILENAME              },
+  { "amoeba.turning_to_gem",                   "pling.wav"                     },
+  { "amoeba.turning_to_gem.mode_loop",         "false"                         },
+  { "amoeba.turning_to_rock",                  "klopf.wav"                     },
+  { "amoeba.turning_to_rock.mode_loop",                "false"                         },
+  { "speed_pill.collecting",                   "pong.wav"                      },
+  { "dynabomb_increase_number.collecting",     "pong.wav"                      },
+  { "dynabomb_increase_size.collecting",       "pong.wav"                      },
+  { "dynabomb_increase_power.collecting",      "pong.wav"                      },
+  { "[dynabomb].dropping",                     "deng.wav"                      },
+  { "[dynabomb].active",                       "zisch.wav"                     },
+  { "satellite.moving",                                UNDEFINED_FILENAME              },
+  { "satellite.waiting",                       UNDEFINED_FILENAME              },
+  { "satellite.pushing",                       "pusch.wav"                     },
+  { "lamp.activating",                         "deng.wav"                      },
+  { "lamp.deactivating",                       "deng.wav"                      },
+  { "time_orb_full.collecting",                        "gong.wav"                      },
+  { "time_orb_full.impact",                    "deng.wav"                      },
+  { "time_orb_empty.pushing",                  "pusch.wav"                     },
+  { "time_orb_empty.impact",                   "deng.wav"                      },
+  { "game_of_life.waiting",                    UNDEFINED_FILENAME              },
+  { "game_of_life.growing",                    "amoebe.wav"                    },
+  { "biomaze.waiting",                         UNDEFINED_FILENAME              },
+  { "biomaze.growing",                         "amoebe.wav"                    },
+  { "pacman.moving",                           UNDEFINED_FILENAME              },
+  { "pacman.waiting",                          UNDEFINED_FILENAME              },
+  { "pacman.digging",                          UNDEFINED_FILENAME              },
+  { "dark_yamyam.moving",                      UNDEFINED_FILENAME              },
+  { "dark_yamyam.waiting",                     "njam.wav"                      },
+  { "dark_yamyam.digging",                     UNDEFINED_FILENAME              },
+  { "penguin.moving",                          UNDEFINED_FILENAME              },
+  { "penguin.waiting",                         UNDEFINED_FILENAME              },
+  { "pig.moving",                              UNDEFINED_FILENAME              },
+  { "pig.waiting",                             UNDEFINED_FILENAME              },
+  { "pig.digging",                             UNDEFINED_FILENAME              },
+  { "dragon.moving",                           UNDEFINED_FILENAME              },
+  { "dragon.waiting",                          UNDEFINED_FILENAME              },
+  { "dragon.attacking",                                UNDEFINED_FILENAME              },
 
   // sounds for Mirror Magic style elements and actions
-  { "[mm_mcduffin].hitting",           "autsch.wav"                    },
-  { "[mm_mirror].hitting",             "laser.wav"                     },
-  { "[mm_mirror_fixed].hitting",       "laser.wav"                     },
-  { "[mm_prism].hitting",              "laser.wav"                     },
-  { "[mm_exit].hitting",               "holz.wav"                      },
-  { "[mm_exit].opening",               "kling.wav"                     },
-  { "mm_exit_open.hitting",            UNDEFINED_FILENAME              },
-  { "[df_mirror].hitting",             "laser.wav"                     },
-  { "[df_mirror_rotating].hitting",    "laser.wav"                     },
-  { "[df_refractor].hitting",          "laser.wav"                     },
-  { "[df_receiver].hitting",           "holz.wav"                      },
-  { "[df_receiver].opening",           "kling.wav"                     },
-  { "[mm_wooden_wall].hitting",                "holz.wav"                      },
-  { "[mm_wooden_block].hitting",       "holz.wav"                      },
-  { "[mm_wooden_block].pushing",       "bong.wav"                      },
-  { "[mm_wooden_lock].hitting",                "holz.wav"                      },
-  { "[mm_wooden_grid_fixed].hitting",  "holz.wav"                      },
-  { "[mm_fuse].hitting",               "holz.wav"                      },
-  { "[mm_ice_wall].hitting",           "holz.wav"                      },
-  { "[mm_ice_wall].shrinking",         "slurp.wav"                     },
-  { "[mm_amoeba_wall].hitting",                "holz.wav"                      },
-  { "[mm_amoeba_wall].growing",                "amoebe.wav"                    },
-  { "[mm_amoeba_wall].growing.mode_loop","false"                       },
-  { "[df_wooden_wall].hitting",                "holz.wav"                      },
-  { "[df_wooden_grid_fixed].hitting",  "holz.wav"                      },
-  { "[df_wooden_grid_rotating].hitting","holz.wav"                     },
-  { "[mm_steel_wall].hitting",         "hui.wav"                       },
-  { "[mm_steel_grid_fixed].hitting",   "hui.wav"                       },
-  { "[mm_steel_block].hitting",                "hui.wav"                       },
-  { "[mm_steel_block].pushing",                "bong.wav"                      },
-  { "[mm_steel_lock].hitting",         "hui.wav"                       },
-  { "[df_steel_wall].hitting",         "hui.wav"                       },
-  { "[df_steel_grid_fixed].hitting",   "hui.wav"                       },
-  { "[df_steel_grid_rotating].hitting",        "hui.wav"                       },
-
-  { "[mm_pacman].exploding",           "quiek.wav"                     },
-  { "[mm_mcduffin].exploding",         "roaaar.wav"                    },
-  { "[mm_bomb].exploding",             "roaaar.wav"                    },
-  { "[mm_key].exploding",              "kling.wav"                     },
-  { "[mm_steel_lock].exploding",       "whoosh.wav"                    },
-  { "[mm_wooden_lock].exploding",      "whoosh.wav"                    },
-
-  // sounds not associated to game elements (used for menu screens etc.)
+  { "[mm_mcduffin].hitting",                   "autsch.wav"                    },
+  { "[mm_mirror].hitting",                     "laser.wav"                     },
+  { "[mm_mirror_fixed].hitting",               "laser.wav"                     },
+  { "[mm_prism].hitting",                      "laser.wav"                     },
+  { "[mm_exit].hitting",                       "holz.wav"                      },
+  { "[mm_exit].opening",                       "kling.wav"                     },
+  { "mm_exit_open.hitting",                    UNDEFINED_FILENAME              },
+  { "[df_mirror].hitting",                     "laser.wav"                     },
+  { "[df_mirror_rotating].hitting",            "laser.wav"                     },
+  { "[df_refractor].hitting",                  "laser.wav"                     },
+  { "[df_receiver].hitting",                   "holz.wav"                      },
+  { "[df_receiver].opening",                   "kling.wav"                     },
+  { "[mm_wooden_wall].hitting",                        "holz.wav"                      },
+  { "[mm_wooden_block].hitting",               "holz.wav"                      },
+  { "[mm_wooden_block].pushing",               "bong.wav"                      },
+  { "[mm_wooden_lock].hitting",                        "holz.wav"                      },
+  { "[mm_wooden_grid_fixed].hitting",          "holz.wav"                      },
+  { "[mm_fuse].hitting",                       "holz.wav"                      },
+  { "[mm_ice_wall].hitting",                   "holz.wav"                      },
+  { "[mm_ice_wall].shrinking",                 "slurp.wav"                     },
+  { "[mm_amoeba_wall].hitting",                        "holz.wav"                      },
+  { "[mm_amoeba_wall].growing",                        "amoebe.wav"                    },
+  { "[mm_amoeba_wall].growing.mode_loop",      "false"                         },
+  { "[df_wooden_wall].hitting",                        "holz.wav"                      },
+  { "[df_wooden_grid_fixed].hitting",          "holz.wav"                      },
+  { "[df_wooden_grid_rotating].hitting",       "holz.wav"                      },
+  { "[mm_steel_wall].hitting",                 "hui.wav"                       },
+  { "[mm_steel_grid_fixed].hitting",           "hui.wav"                       },
+  { "[mm_steel_block].hitting",                        "hui.wav"                       },
+  { "[mm_steel_block].pushing",                        "bong.wav"                      },
+  { "[mm_steel_lock].hitting",                 "hui.wav"                       },
+  { "[df_steel_wall].hitting",                 "hui.wav"                       },
+  { "[df_steel_grid_fixed].hitting",           "hui.wav"                       },
+  { "[df_steel_grid_rotating].hitting",                "hui.wav"                       },
+
+  { "[mm_pacman].exploding",                   "quiek.wav"                     },
+  { "[mm_mcduffin].exploding",                 "roaaar.wav"                    },
+  { "[mm_bomb].exploding",                     "roaaar.wav"                    },
+  { "[mm_key].exploding",                      "kling.wav"                     },
+  { "[mm_steel_lock].exploding",               "whoosh.wav"                    },
+  { "[mm_wooden_lock].exploding",              "whoosh.wav"                    },
+
+
+  // ==========================================================================
+  // sound definitions not associated with game elements (menu screens etc.)
+  // ==========================================================================
+
   // keyword to stop parser: "NO_MORE_ELEMENT_SOUNDS" <-- do not change!
 
+  // sounds for Boulder Dash style elements and actions
+  { "bdx_diamond.falling.RANDOM_1",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_2",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_3",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_4",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_5",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_6",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_7",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.falling.RANDOM_8",            UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_1",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_2",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_3",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_4",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_5",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_6",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_7",             UNDEFINED_FILENAME              },
+  { "bdx_diamond.impact.RANDOM_8",             UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_1",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_2",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_3",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_4",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_5",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_6",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_7",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.falling.RANDOM_8",     UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_1",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_2",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_3",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_4",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_5",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_6",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_7",      UNDEFINED_FILENAME              },
+  { "bdx_flying_diamond.impact.RANDOM_8",      UNDEFINED_FILENAME              },
+
   // sounds for other game actions
-  { "game.starting",                   UNDEFINED_FILENAME              },
-  { "game.leveltime_charging",         "fuel.wav"                      },
-  { "game.health_charging",            "warnton.wav"                   },
-  { "game.running_out_of_time",                "gong.wav"                      },
-  { "game.leveltime_bonus",            "sirr.wav"                      },
-  { "game.health_bonus",               "sirr.wav"                      },
-  { "game.losing",                     "lachen.wav"                    },
-  { "game.winning",                    UNDEFINED_FILENAME              },
-  { "game.sokoban_solving",            "buing.wav"                     },
+  { "game.starting",                           UNDEFINED_FILENAME              },
+  { "game.leveltime_charging",                 "fuel.wav"                      },
+  { "game.health_charging",                    "warnton.wav"                   },
+  { "game.running_out_of_time",                        "gong.wav"                      },
+  { "game.running_out_of_time_10",             UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_9",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_8",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_7",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_6",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_5",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_4",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_3",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_2",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_1",              UNDEFINED_FILENAME              },
+  { "game.running_out_of_time_0",              UNDEFINED_FILENAME              },
+  { "game.leveltime_bonus",                    "sirr.wav"                      },
+  { "game.health_bonus",                       "sirr.wav"                      },
+  { "game.timeout",                            UNDEFINED_FILENAME              },
+  { "game.losing",                             UNDEFINED_FILENAME              },
+  { "game.winning",                            UNDEFINED_FILENAME              },
+  { "game.sokoban_solving",                    "buing.wav"                     },
 
   // sounds for other non-game actions
-  { "door.opening",                    "door.wav"                      },
-  { "door.closing",                    "door.wav"                      },
-  { "door_1.opening",                  UNDEFINED_FILENAME              },
-  { "door_1.closing",                  UNDEFINED_FILENAME              },
-  { "door_2.opening",                  UNDEFINED_FILENAME              },
-  { "door_2.closing",                  UNDEFINED_FILENAME              },
+  { "door.opening",                            "door.wav"                      },
+  { "door.closing",                            "door.wav"                      },
+  { "door_1.opening",                          UNDEFINED_FILENAME              },
+  { "door_1.closing",                          UNDEFINED_FILENAME              },
+  { "door_2.opening",                          UNDEFINED_FILENAME              },
+  { "door_2.closing",                          UNDEFINED_FILENAME              },
 
-  { "request.opening",                 UNDEFINED_FILENAME              },
-  { "request.closing",                 UNDEFINED_FILENAME              },
+  { "request.opening",                         UNDEFINED_FILENAME              },
+  { "request.closing",                         UNDEFINED_FILENAME              },
 
   // sounds for menu actions
-  { "menu.item.activating",            "empty.wav"                     },
-  { "menu.item.selecting",             "base.wav"                      },
-
-  { "menu.button.pressing",            UNDEFINED_FILENAME              },
-  { "menu.button.releasing",           UNDEFINED_FILENAME              },
-
-  { "background.TITLE_INITIAL",                UNDEFINED_FILENAME              },
-  { "background.TITLE",                        UNDEFINED_FILENAME              },
-  { "background.MAIN",                 UNDEFINED_FILENAME              },
-  { "background.NAMES",                        UNDEFINED_FILENAME              },
-  { "background.LEVELS",               UNDEFINED_FILENAME              },
-  { "background.LEVELNR",              UNDEFINED_FILENAME              },
-  { "background.SCORES",               "halloffame.wav"                },
-  { "background.SCORES.mode_loop",     "false"                         },
-  { "background.EDITOR",               UNDEFINED_FILENAME              },
-  { "background.INFO",                 UNDEFINED_FILENAME              },
-  { "background.SETUP",                        UNDEFINED_FILENAME              },
-
-  { "background.titlescreen_initial_1",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_2",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_3",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_4",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_initial_5",        UNDEFINED_FILENAME              },
-  { "background.titlescreen_1",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_2",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_3",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_4",                UNDEFINED_FILENAME              },
-  { "background.titlescreen_5",                UNDEFINED_FILENAME              },
-  { "background.titlemessage_initial_1",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_2",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_3",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_4",UNDEFINED_FILENAME             },
-  { "background.titlemessage_initial_5",UNDEFINED_FILENAME             },
-  { "background.titlemessage_1",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_2",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_3",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_4",       UNDEFINED_FILENAME              },
-  { "background.titlemessage_5",       UNDEFINED_FILENAME              },
-
-  { NULL,                              NULL                            }
+  { "menu.item.activating",                    "empty.wav"                     },
+  { "menu.item.selecting",                     "base.wav"                      },
+
+  { "menu.button.pressing",                    UNDEFINED_FILENAME              },
+  { "menu.button.releasing",                   UNDEFINED_FILENAME              },
+
+  { "background.TITLE_INITIAL",                        UNDEFINED_FILENAME              },
+  { "background.TITLE",                                UNDEFINED_FILENAME              },
+  { "background.MAIN",                         UNDEFINED_FILENAME              },
+  { "background.NAMES",                                UNDEFINED_FILENAME              },
+  { "background.LEVELS",                       UNDEFINED_FILENAME              },
+  { "background.LEVELNR",                      UNDEFINED_FILENAME              },
+  { "background.SCORES",                       "halloffame.wav"                },
+  { "background.SCORES.mode_loop",             "false"                         },
+  { "background.EDITOR",                       UNDEFINED_FILENAME              },
+  { "background.INFO",                         UNDEFINED_FILENAME              },
+  { "background.INFO[ELEMENTS]",               UNDEFINED_FILENAME              },
+  { "background.INFO[CREDITS]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[PROGRAM]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[VERSION]",                        UNDEFINED_FILENAME              },
+  { "background.INFO[LEVELSET]",               UNDEFINED_FILENAME              },
+  { "background.SETUP",                                UNDEFINED_FILENAME              },
+
+  { "background.titlescreen_initial_1",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_2",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_3",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_4",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_initial_5",                UNDEFINED_FILENAME              },
+  { "background.titlescreen_1",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_2",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_3",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_4",                        UNDEFINED_FILENAME              },
+  { "background.titlescreen_5",                        UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_1",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_2",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_3",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_4",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_initial_5",       UNDEFINED_FILENAME              },
+  { "background.titlemessage_1",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_2",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_3",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_4",               UNDEFINED_FILENAME              },
+  { "background.titlemessage_5",               UNDEFINED_FILENAME              },
+
+
+  // ==========================================================================
+  // non-sound definitions
+  // ==========================================================================
+
+  // the following directives are not associated with a sound, but
+  // probably make sense to be defined in "soundsinfo.conf", too
+
+  // keyword to start parser: "CONFIG_VARS_START" <-- do not change!
+
+  { "game.use_native_bd_sound_engine",         "false"                         },
+
+  { NULL,                                      NULL                            }
 };
index 282c530025ca3a893370b3080e65f4392f798d89..0ab5722197222ae67171c807185645aeb65f146c 100644 (file)
 
 #define ED_SETTINGS_LEVEL_TABS_X       (editor.settings.tabs.x)
 #define ED_SETTINGS_LEVEL_TABS_Y       (editor.settings.tabs.y)
+#define ED_SETTINGS_ENGINE_TABS_X      (editor.settings.tabs.x)
+#define ED_SETTINGS_ENGINE_TABS_Y      (editor.settings.tabs.y +       \
+                                        ED_TABBUTTON_YSIZE +           \
+                                        ED_GADGET_TINY_DISTANCE +      \
+                                        ED_TAB_BAR_HEIGHT +            \
+                                        ED_GADGET_TEXT_DISTANCE)
 #define ED_SETTINGS_ELEMENT_TABS_X     (editor.settings.tabs.x)
 #define ED_SETTINGS_ELEMENT_TABS_Y     (editor.settings.tabs.y +       \
                                         editor.settings.tabs.yoffset2)
                                         ED_SETTINGS_TABS_YOFFSET +     \
                                         getFontHeight(FONT_TEXT_1) +   \
                                         ED_GADGET_TEXT_DISTANCE)
+#define ED_ENGINE_TABS_XSTART          (ED_SETTINGS_ENGINE_TABS_X)
+#define ED_ENGINE_TABS_YSTART          (ED_SETTINGS_ENGINE_TABS_Y)
+#define ED_ENGINE_SETTINGS_XSTART      (ED_SETTINGS_ENGINE_TABS_X +    \
+                                        ED_SETTINGS_TABS_XOFFSET)
+#define ED_ENGINE_SETTINGS_YSTART      (ED_SETTINGS_ENGINE_TABS_Y +    \
+                                        ED_TABBUTTON_YSIZE +           \
+                                        ED_GADGET_TINY_DISTANCE +      \
+                                        ED_TAB_BAR_HEIGHT +            \
+                                        ED_SETTINGS_TABS_YOFFSET +     \
+                                        getFontHeight(FONT_TEXT_1) +   \
+                                        ED_GADGET_TEXT_DISTANCE)
 #define ED_ELEMENT_TABS_XSTART         (ED_SETTINGS_ELEMENT_TABS_X)
 #define ED_ELEMENT_TABS_YSTART         (ED_SETTINGS_ELEMENT_TABS_Y)
 #define ED_ELEMENT_SETTINGS_XSTART     (ED_SETTINGS_ELEMENT_TABS_X +   \
 #define ED_POS_LEVEL_TABS_LAST         (2 * ED_POS_RANGE - 1)
 #define ED_POS_LEVEL_SETTINGS_FIRST    (2 * ED_POS_RANGE)
 #define ED_POS_LEVEL_SETTINGS_LAST     (3 * ED_POS_RANGE - 1)
-#define ED_POS_ELEMENT_TABS_FIRST      (3 * ED_POS_RANGE)
-#define ED_POS_ELEMENT_TABS_LAST       (4 * ED_POS_RANGE - 1)
-#define ED_POS_ELEMENT_SETTINGS_FIRST  (4 * ED_POS_RANGE)
-#define ED_POS_ELEMENT_SETTINGS_LAST   (5 * ED_POS_RANGE - 1)
+#define ED_POS_ENGINE_TABS_FIRST       (3 * ED_POS_RANGE)
+#define ED_POS_ENGINE_TABS_LAST                (4 * ED_POS_RANGE - 1)
+#define ED_POS_ENGINE_SETTINGS_FIRST   (4 * ED_POS_RANGE)
+#define ED_POS_ENGINE_SETTINGS_LAST    (5 * ED_POS_RANGE - 1)
+#define ED_POS_ELEMENT_TABS_FIRST      (5 * ED_POS_RANGE)
+#define ED_POS_ELEMENT_TABS_LAST       (6 * ED_POS_RANGE - 1)
+#define ED_POS_ELEMENT_SETTINGS_FIRST  (6 * ED_POS_RANGE)
+#define ED_POS_ELEMENT_SETTINGS_LAST   (7 * ED_POS_RANGE - 1)
 
 #define ED_LEVEL_TABS_XPOS(n)          (ED_POS_LEVEL_TABS_FIRST + (n))
 #define ED_LEVEL_TABS_YPOS(n)          (ED_POS_LEVEL_TABS_FIRST + (n))
 #define ED_LEVEL_SETTINGS_XPOS(n)      (ED_POS_LEVEL_SETTINGS_FIRST + (n))
 #define ED_LEVEL_SETTINGS_YPOS(n)      (ED_POS_LEVEL_SETTINGS_FIRST + (n))
 
+#define ED_ENGINE_TABS_XPOS(n)         (ED_POS_ENGINE_TABS_FIRST + (n))
+#define ED_ENGINE_TABS_YPOS(n)         (ED_POS_ENGINE_TABS_FIRST + (n))
+
+#define ED_ENGINE_SETTINGS_XPOS(n)     (ED_POS_ENGINE_SETTINGS_FIRST + (n))
+#define ED_ENGINE_SETTINGS_YPOS(n)     (ED_POS_ENGINE_SETTINGS_FIRST + (n))
+
 #define ED_ELEMENT_TABS_XPOS(n)                (ED_POS_ELEMENT_TABS_FIRST + (n))
 #define ED_ELEMENT_TABS_YPOS(n)                (ED_POS_ELEMENT_TABS_FIRST + (n))
 
                                       (n) <= ED_POS_LEVEL_TABS_LAST)
 #define IS_POS_LEVEL_SETTINGS(n)      ((n) >= ED_POS_LEVEL_SETTINGS_FIRST && \
                                       (n) <= ED_POS_LEVEL_SETTINGS_LAST)
+#define IS_POS_ENGINE_TABS(n)        ((n) >= ED_POS_ENGINE_TABS_FIRST && \
+                                      (n) <= ED_POS_ENGINE_TABS_LAST)
+#define IS_POS_ENGINE_SETTINGS(n)     ((n) >= ED_POS_ENGINE_SETTINGS_FIRST && \
+                                      (n) <= ED_POS_ENGINE_SETTINGS_LAST)
 #define IS_POS_ELEMENT_TABS(n)       ((n) >= ED_POS_ELEMENT_TABS_FIRST && \
                                       (n) <= ED_POS_ELEMENT_TABS_LAST)
 #define IS_POS_ELEMENT_SETTINGS(n)    ((n) >= ED_POS_ELEMENT_SETTINGS_FIRST && \
 
 #define ED_LEVEL_TABS_LINE(n)          ((n) - ED_POS_LEVEL_TABS_FIRST)
 #define ED_LEVEL_SETTINGS_LINE(n)      ((n) - ED_POS_LEVEL_SETTINGS_FIRST)
+#define ED_ENGINE_TABS_LINE(n)         ((n) - ED_POS_ENGINE_TABS_FIRST)
+#define ED_ENGINE_SETTINGS_LINE(n)     ((n) - ED_POS_ENGINE_SETTINGS_FIRST)
 #define ED_ELEMENT_TABS_LINE(n)                ((n) - ED_POS_ELEMENT_TABS_FIRST)
 #define ED_ELEMENT_SETTINGS_LINE(n)    ((n) - ED_POS_ELEMENT_SETTINGS_FIRST)
 
 #define ED_LEVEL_SETTINGS_Y(n)         (ED_LEVEL_SETTINGS_YSTART +     \
                                         (n) * ED_SETTINGS_YOFFSET)
 
+#define ED_ENGINE_TABS_X(n)            (ED_ENGINE_TABS_XSTART +        \
+                                        (n) * ED_SETTINGS_TABS_XOFFSET)
+#define ED_ENGINE_TABS_Y(n)            (ED_ENGINE_TABS_YSTART +        \
+                                        (n) * ED_SETTINGS_TABS_YOFFSET)
+
+#define ED_ENGINE_SETTINGS_X(n)                (ED_ENGINE_SETTINGS_XSTART +    \
+                                        (n) * ED_SETTINGS_XOFFSET)
+#define ED_ENGINE_SETTINGS_Y(n)                (ED_ENGINE_SETTINGS_YSTART +    \
+                                        (n) * ED_SETTINGS_YOFFSET)
+
 #define ED_ELEMENT_TABS_X(n)           (ED_ELEMENT_TABS_XSTART +       \
                                         (n) * ED_SETTINGS_TABS_XOFFSET)
 #define ED_ELEMENT_TABS_Y(n)           (ED_ELEMENT_TABS_YSTART +       \
 #define ED_POS_TO_LEVEL_SETTINGS_Y(n)  \
   (ED_LEVEL_SETTINGS_Y(ED_LEVEL_SETTINGS_LINE(n)))
 
+#define ED_POS_TO_ENGINE_TABS_X(n)     \
+  (ED_ENGINE_TABS_X(ED_ENGINE_TABS_LINE(n)))
+#define ED_POS_TO_ENGINE_TABS_Y(n)     \
+  (ED_ENGINE_TABS_Y(ED_ENGINE_TABS_LINE(n)))
+
+#define ED_POS_TO_ENGINE_SETTINGS_X(n) \
+  (ED_ENGINE_SETTINGS_X(ED_ENGINE_SETTINGS_LINE(n)))
+#define ED_POS_TO_ENGINE_SETTINGS_Y(n) \
+  (ED_ENGINE_SETTINGS_Y(ED_ENGINE_SETTINGS_LINE(n)))
+
 #define ED_POS_TO_ELEMENT_TABS_X(n)    \
   (ED_ELEMENT_TABS_X(ED_ELEMENT_TABS_LINE(n)))
 #define ED_POS_TO_ELEMENT_TABS_Y(n)    \
                                         ED_POS_TO_LEVEL_TABS_X(n) : \
                                         IS_POS_LEVEL_SETTINGS(n) ?     \
                                         ED_POS_TO_LEVEL_SETTINGS_X(n) : \
+                                        IS_POS_ENGINE_TABS(n) ?        \
+                                        ED_POS_TO_ENGINE_TABS_X(n) : \
+                                        IS_POS_ENGINE_SETTINGS(n) ?    \
+                                        ED_POS_TO_ENGINE_SETTINGS_X(n) : \
                                         IS_POS_ELEMENT_TABS(n) ?       \
                                         ED_POS_TO_ELEMENT_TABS_X(n) : \
                                         IS_POS_ELEMENT_SETTINGS(n) ?   \
                                         ED_POS_TO_LEVEL_TABS_Y(n) : \
                                         IS_POS_LEVEL_SETTINGS(n) ?     \
                                         ED_POS_TO_LEVEL_SETTINGS_Y(n) : \
+                                        IS_POS_ENGINE_TABS(n) ?        \
+                                        ED_POS_TO_ENGINE_TABS_Y(n) : \
+                                        IS_POS_ENGINE_SETTINGS(n) ?    \
+                                        ED_POS_TO_ENGINE_SETTINGS_Y(n) : \
                                         IS_POS_ELEMENT_TABS(n) ?       \
                                         ED_POS_TO_ELEMENT_TABS_Y(n) : \
                                         IS_POS_ELEMENT_SETTINGS(n) ?   \
@@ -382,7 +443,7 @@ enum
   GADGET_ID_PICK_ELEMENT,
 
   GADGET_ID_UNDO,
-  GADGET_ID_INFO,
+  GADGET_ID_CONF,
   GADGET_ID_SAVE,
   GADGET_ID_CLEAR,
   GADGET_ID_TEST,
@@ -429,6 +490,24 @@ enum
   GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,
   GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,
   GADGET_ID_LEVELSET_NUM_LEVELS_UP,
+  GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,
+  GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,
+  GADGET_ID_BD_CYCLE_DELAY_MS_UP,
+  GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,
+  GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,
+  GADGET_ID_BD_CYCLE_DELAY_C64_UP,
+  GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,
+  GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,
+  GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
+  GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,
+  GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,
+  GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
+  GADGET_ID_BD_PUSHING_PROB_DOWN,
+  GADGET_ID_BD_PUSHING_PROB_TEXT,
+  GADGET_ID_BD_PUSHING_PROB_UP,
+  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN,
+  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT,
+  GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
   GADGET_ID_ELEMENT_VALUE1_DOWN,
   GADGET_ID_ELEMENT_VALUE1_TEXT,
   GADGET_ID_ELEMENT_VALUE1_UP,
@@ -459,6 +538,9 @@ enum
   GADGET_ID_INVENTORY_SIZE_DOWN,
   GADGET_ID_INVENTORY_SIZE_TEXT,
   GADGET_ID_INVENTORY_SIZE_UP,
+  GADGET_ID_MM_BALL_CONTENT_DOWN,
+  GADGET_ID_MM_BALL_CONTENT_TEXT,
+  GADGET_ID_MM_BALL_CONTENT_UP,
   GADGET_ID_CUSTOM_SCORE_DOWN,
   GADGET_ID_CUSTOM_SCORE_TEXT,
   GADGET_ID_CUSTOM_SCORE_UP,
@@ -535,10 +617,52 @@ enum
   GADGET_ID_MAGIC_BALL_CONTENT_7,
   GADGET_ID_ANDROID_CONTENT,
   GADGET_ID_AMOEBA_CONTENT,
+  GADGET_ID_BD_SNAP_ELEMENT,
+  GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,
+  GADGET_ID_BD_MAGIC_WALL_ROCK_TO,
+  GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
+  GADGET_ID_BD_MAGIC_WALL_NUT_TO,
+  GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
+  GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
+  GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
+  GADGET_ID_BD_AMOEBA_1_CONTENT_TOO_BIG,
+  GADGET_ID_BD_AMOEBA_1_CONTENT_ENCLOSED,
+  GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
+  GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
+  GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
+  GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
+  GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
+  GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
+  GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
+  GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
+  GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
+  GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
+  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_NUT_CONTENT,
+  GADGET_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
+  GADGET_ID_BD_SAND_LOOKS_LIKE,
+  GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,
+  GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
+  GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
+  GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
+  GADGET_ID_BD_FIREFLY_1_EXPLODES_TO,
+  GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,
+  GADGET_ID_BD_BUTTERFLY_1_EXPLODES_TO,
+  GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,
+  GADGET_ID_BD_STONEFLY_EXPLODES_TO,
+  GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,
+  GADGET_ID_BD_DIAMOND_BIRTH_TURNS_TO,
+  GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,
+  GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,
+  GADGET_ID_BD_EXPLOSION_TURNS_TO,
   GADGET_ID_START_ELEMENT,
   GADGET_ID_ARTWORK_ELEMENT,
   GADGET_ID_EXPLOSION_ELEMENT,
   GADGET_ID_INVENTORY_CONTENT,
+  GADGET_ID_MM_BALL_CONTENT,
   GADGET_ID_CUSTOM_GRAPHIC,
   GADGET_ID_CUSTOM_CONTENT,
   GADGET_ID_CUSTOM_MOVE_ENTER,
@@ -556,6 +680,13 @@ enum
   GADGET_ID_LEVEL_AUTHOR,
   GADGET_ID_LEVELSET_NAME,
   GADGET_ID_LEVELSET_AUTHOR,
+  GADGET_ID_BD_COLOR_TEXT_B,
+  GADGET_ID_BD_COLOR_TEXT_0,
+  GADGET_ID_BD_COLOR_TEXT_1,
+  GADGET_ID_BD_COLOR_TEXT_2,
+  GADGET_ID_BD_COLOR_TEXT_3,
+  GADGET_ID_BD_COLOR_TEXT_4,
+  GADGET_ID_BD_COLOR_TEXT_5,
   GADGET_ID_ELEMENT_NAME,
 
   // text area identifiers
@@ -568,8 +699,19 @@ enum
   GADGET_ID_TIME_SCORE_BASE,
   GADGET_ID_GAME_ENGINE_TYPE,
   GADGET_ID_LEVELSET_SAVE_MODE,
+  GADGET_ID_BD_SCHEDULING_TYPE,
+  GADGET_ID_BD_COLOR_TYPE,
+  GADGET_ID_BD_COLOR_C64_B,
+  GADGET_ID_BD_COLOR_C64_0,
+  GADGET_ID_BD_COLOR_C64_1,
+  GADGET_ID_BD_COLOR_C64_2,
+  GADGET_ID_BD_COLOR_C64_3,
+  GADGET_ID_BD_COLOR_C64_4,
+  GADGET_ID_BD_COLOR_C64_5,
   GADGET_ID_WIND_DIRECTION,
   GADGET_ID_PLAYER_SPEED,
+  GADGET_ID_BD_GRAVITY_DIRECTION,
+  GADGET_ID_MM_BALL_CHOICE_MODE,
   GADGET_ID_CUSTOM_WALK_TO_ACTION,
   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
   GADGET_ID_CUSTOM_DEADLINESS,
@@ -598,9 +740,12 @@ enum
 
   // textbutton identifiers
 
-  GADGET_ID_LEVELINFO_LEVEL,
-  GADGET_ID_LEVELINFO_LEVELSET,
-  GADGET_ID_LEVELINFO_EDITOR,
+  GADGET_ID_LEVELCONFIG_LEVEL,
+  GADGET_ID_LEVELCONFIG_LEVELSET,
+  GADGET_ID_LEVELCONFIG_EDITOR,
+  GADGET_ID_LEVELCONFIG_ENGINE,
+  GADGET_ID_ENGINECONFIG_CONFIG,
+  GADGET_ID_ENGINECONFIG_COLORS,
   GADGET_ID_PROPERTIES_INFO,
   GADGET_ID_PROPERTIES_CONFIG,
   GADGET_ID_PROPERTIES_CONFIG_1,
@@ -611,6 +756,7 @@ enum
   GADGET_ID_SAVE_LEVELSET,
   GADGET_ID_ADD_CHANGE_PAGE,
   GADGET_ID_DEL_CHANGE_PAGE,
+  GADGET_ID_BD_SET_RANDOM_COLORS,
 
   // graphicbutton identifiers
 
@@ -643,6 +789,11 @@ enum
   GADGET_ID_RANDOM_PERCENTAGE,
   GADGET_ID_RANDOM_QUANTITY,
   GADGET_ID_RANDOM_RESTRICTED,
+  GADGET_ID_BD_INTERMISSION,
+  GADGET_ID_BD_PAL_TIMING,
+  GADGET_ID_BD_LINE_SHIFTING_BORDERS,
+  GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,
+  GADGET_ID_BD_SHORT_EXPLOSIONS,
   GADGET_ID_STICK_ELEMENT,
   GADGET_ID_EM_SLIPPERY_GEMS,
   GADGET_ID_EM_EXPLODES_BY_FIRE,
@@ -674,6 +825,32 @@ enum
   GADGET_ID_CAN_FALL_INTO_ACID,
   GADGET_ID_CAN_MOVE_INTO_ACID,
   GADGET_ID_DONT_COLLIDE_WITH,
+  GADGET_ID_BD_DIAGONAL_MOVEMENTS,
+  GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,
+  GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
+  GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,
+  GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
+  GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
+  GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,
+  GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
+  GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
+  GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
+  GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+  GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+  GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
+  GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+  GADGET_ID_BD_SLIME_IS_PREDICTABLE,
+  GADGET_ID_BD_CHANGE_EXPANDING_WALL,
+  GADGET_ID_BD_REPLICATORS_ACTIVE,
+  GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,
+  GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,
+  GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,
+  GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,
+  GADGET_ID_BD_INFINITE_ROCKETS,
+  GADGET_ID_BD_CREATURES_START_BACKWARDS,
+  GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,
+  GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,
+  GADGET_ID_BD_GRAVITY_AFFECTS_ALL,
   GADGET_ID_ENVELOPE_AUTOWRAP,
   GADGET_ID_ENVELOPE_CENTERED,
   GADGET_ID_MM_LASER_RED,
@@ -682,6 +859,8 @@ enum
   GADGET_ID_DF_LASER_RED,
   GADGET_ID_DF_LASER_GREEN,
   GADGET_ID_DF_LASER_BLUE,
+  GADGET_ID_ROTATE_MM_BALL_CONTENT,
+  GADGET_ID_EXPLODE_MM_BALL,
   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
   GADGET_ID_CUSTOM_CAN_EXPLODE,
   GADGET_ID_CUSTOM_EXPLODE_FIRE,
@@ -740,6 +919,12 @@ enum
   ED_COUNTER_ID_LEVEL_RANDOM_SEED,
   ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
   ED_COUNTER_ID_LEVEL_RANDOM,
+  ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
+  ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
+  ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
+  ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
+  ED_COUNTER_ID_BD_PUSHING_PROB,
+  ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
   ED_COUNTER_ID_ELEMENT_VALUE1,
   ED_COUNTER_ID_ELEMENT_VALUE2,
   ED_COUNTER_ID_ELEMENT_VALUE3,
@@ -750,6 +935,7 @@ enum
   ED_COUNTER_ID_ENVELOPE_XSIZE,
   ED_COUNTER_ID_ENVELOPE_YSIZE,
   ED_COUNTER_ID_INVENTORY_SIZE,
+  ED_COUNTER_ID_MM_BALL_CONTENT,
   ED_COUNTER_ID_CUSTOM_SCORE,
   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
@@ -825,6 +1011,13 @@ enum
   ED_TEXTINPUT_ID_LEVEL_AUTHOR,
   ED_TEXTINPUT_ID_LEVELSET_NAME,
   ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_B,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_0,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_1,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_2,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_3,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_4,
+  ED_TEXTINPUT_ID_BD_COLOR_TEXT_5,
   ED_TEXTINPUT_ID_ELEMENT_NAME,
 
   ED_NUM_TEXTINPUT
@@ -836,6 +1029,9 @@ enum
 #define ED_TEXTINPUT_ID_LEVELSET_FIRST ED_TEXTINPUT_ID_LEVELSET_NAME
 #define ED_TEXTINPUT_ID_LEVELSET_LAST  ED_TEXTINPUT_ID_LEVELSET_AUTHOR
 
+#define ED_TEXTINPUT_ID_COLORS_FIRST   ED_TEXTINPUT_ID_BD_COLOR_TEXT_B
+#define ED_TEXTINPUT_ID_COLORS_LAST    ED_TEXTINPUT_ID_BD_COLOR_TEXT_5
+
 // values for text area gadgets
 enum
 {
@@ -854,8 +1050,19 @@ enum
   ED_SELECTBOX_ID_TIME_SCORE_BASE,
   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
+  ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
+  ED_SELECTBOX_ID_BD_COLOR_TYPE,
+  ED_SELECTBOX_ID_BD_COLOR_C64_B,
+  ED_SELECTBOX_ID_BD_COLOR_C64_0,
+  ED_SELECTBOX_ID_BD_COLOR_C64_1,
+  ED_SELECTBOX_ID_BD_COLOR_C64_2,
+  ED_SELECTBOX_ID_BD_COLOR_C64_3,
+  ED_SELECTBOX_ID_BD_COLOR_C64_4,
+  ED_SELECTBOX_ID_BD_COLOR_C64_5,
   ED_SELECTBOX_ID_WIND_DIRECTION,
   ED_SELECTBOX_ID_PLAYER_SPEED,
+  ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
+  ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
@@ -891,6 +1098,12 @@ enum
 #define ED_SELECTBOX_ID_LEVELSET_FIRST ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
 #define ED_SELECTBOX_ID_LEVELSET_LAST  ED_SELECTBOX_ID_LEVELSET_SAVE_MODE
 
+#define ED_SELECTBOX_ID_ENGINE_FIRST   ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
+#define ED_SELECTBOX_ID_ENGINE_LAST    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE
+
+#define ED_SELECTBOX_ID_COLORS_FIRST   ED_SELECTBOX_ID_BD_COLOR_C64_B
+#define ED_SELECTBOX_ID_COLORS_LAST    ED_SELECTBOX_ID_BD_COLOR_C64_5
+
 #define ED_SELECTBOX_ID_CUSTOM1_FIRST  ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
 #define ED_SELECTBOX_ID_CUSTOM1_LAST   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
 #define ED_SELECTBOX_ID_CUSTOM2_FIRST  ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
@@ -904,9 +1117,12 @@ enum
 // values for textbutton gadgets
 enum
 {
-  ED_TEXTBUTTON_ID_LEVELINFO_LEVEL,
-  ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET,
-  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
+  ED_TEXTBUTTON_ID_ENGINECONFIG_CONFIG,
+  ED_TEXTBUTTON_ID_ENGINECONFIG_COLORS,
   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
@@ -917,12 +1133,16 @@ enum
   ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
   ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
+  ED_TEXTBUTTON_ID_BD_SET_RANDOM_COLORS,
 
   ED_NUM_TEXTBUTTONS
 };
 
-#define ED_TAB_BUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
-#define ED_TAB_BUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
+#define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
+#define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
+
+#define ED_TAB_BUTTON_ID_ENGINECONFIG_FIRST ED_TEXTBUTTON_ID_ENGINECONFIG_CONFIG
+#define ED_TAB_BUTTON_ID_ENGINECONFIG_LAST  ED_TEXTBUTTON_ID_ENGINECONFIG_COLORS
 
 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
@@ -954,6 +1174,11 @@ enum
   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
+  ED_CHECKBUTTON_ID_BD_INTERMISSION,
+  ED_CHECKBUTTON_ID_BD_PAL_TIMING,
+  ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
+  ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
+  ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
   ED_CHECKBUTTON_ID_STICK_ELEMENT,
   ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
   ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
@@ -985,6 +1210,32 @@ enum
   ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
   ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
   ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
+  ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
+  ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
+  ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
+  ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
+  ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
+  ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
+  ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
+  ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
+  ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
+  ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
+  ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+  ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+  ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
+  ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+  ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
+  ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
+  ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
+  ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
+  ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
+  ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
+  ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
+  ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
+  ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
+  ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
+  ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
+  ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
   ED_CHECKBUTTON_ID_MM_LASER_RED,
@@ -993,6 +1244,8 @@ enum
   ED_CHECKBUTTON_ID_DF_LASER_RED,
   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
+  ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
+  ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
@@ -1031,6 +1284,9 @@ enum
 #define ED_CHECKBUTTON_ID_EDITOR_FIRST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 #define ED_CHECKBUTTON_ID_EDITOR_LAST  ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2
 
+#define ED_CHECKBUTTON_ID_ENGINE_FIRST ED_CHECKBUTTON_ID_BD_INTERMISSION
+#define ED_CHECKBUTTON_ID_ENGINE_LAST  ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS
+
 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST        ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
 #define ED_CHECKBUTTON_ID_CUSTOM1_LAST ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
 #define ED_CHECKBUTTON_ID_CUSTOM2_FIRST        ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
@@ -1075,10 +1331,52 @@ enum
   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
   ED_DRAWING_ID_ANDROID_CONTENT,
   ED_DRAWING_ID_AMOEBA_CONTENT,
+  ED_DRAWING_ID_BD_SNAP_ELEMENT,
+  ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
+  ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
+  ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_TOO_BIG,
+  ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_ENCLOSED,
+  ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
+  ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
+  ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
+  ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
+  ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
+  ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
+  ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
+  ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
+  ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
+  ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
+  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_NUT_CONTENT,
+  ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
+  ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
+  ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
+  ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
+  ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
+  ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
+  ED_DRAWING_ID_BD_FIREFLY_1_EXPLODES_TO,
+  ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
+  ED_DRAWING_ID_BD_BUTTERFLY_1_EXPLODES_TO,
+  ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
+  ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
+  ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
+  ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
+  ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
+  ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
+  ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
   ED_DRAWING_ID_START_ELEMENT,
   ED_DRAWING_ID_ARTWORK_ELEMENT,
   ED_DRAWING_ID_EXPLOSION_ELEMENT,
   ED_DRAWING_ID_INVENTORY_CONTENT,
+  ED_DRAWING_ID_MM_BALL_CONTENT,
   ED_DRAWING_ID_CUSTOM_GRAPHIC,
   ED_DRAWING_ID_CUSTOM_CONTENT,
   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
@@ -1114,14 +1412,19 @@ enum
 
 // screens in the level editor
 #define ED_MODE_DRAWING                        0
-#define ED_MODE_INFO                   1
+#define ED_MODE_LEVELCONFIG            1
 #define ED_MODE_PROPERTIES             2
 #define ED_MODE_PALETTE                        3
 
 // sub-screens in the global settings section
-#define ED_MODE_LEVELINFO_LEVEL                ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
-#define ED_MODE_LEVELINFO_LEVELSET     ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET
-#define ED_MODE_LEVELINFO_EDITOR       ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
+#define ED_MODE_LEVELCONFIG_LEVEL      ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
+#define ED_MODE_LEVELCONFIG_LEVELSET   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
+#define ED_MODE_LEVELCONFIG_EDITOR     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
+#define ED_MODE_LEVELCONFIG_ENGINE     ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE
+
+// sub-screens in the engine settings section
+#define ED_MODE_ENGINECONFIG_CONFIG    ED_TEXTBUTTON_ID_ENGINECONFIG_CONFIG
+#define ED_MODE_ENGINECONFIG_COLORS    ED_TEXTBUTTON_ID_ENGINECONFIG_COLORS
 
 // sub-screens in the element properties section
 #define ED_MODE_PROPERTIES_INFO                ED_TEXTBUTTON_ID_PROPERTIES_INFO
@@ -1176,82 +1479,82 @@ static struct
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_SINGLE,         GADGET_ID_SINGLE_ITEMS,
     &editor.button.draw_single,                        GD_TYPE_RADIO_BUTTON,
-    "draw single items",                       's'
+    "Draw single items",                       's'
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_CONNECTED,      GADGET_ID_CONNECTED_ITEMS,
     &editor.button.draw_connected,             GD_TYPE_RADIO_BUTTON,
-    "draw connected items",                    'd'
+    "Draw connected items",                    'd'
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_LINE,           GADGET_ID_LINE,
     &editor.button.draw_line,                  GD_TYPE_RADIO_BUTTON,
-    "draw lines",                              'l'
+    "Draw lines",                              'l'
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_ARC,            GADGET_ID_ARC,
     &editor.button.draw_arc,                   GD_TYPE_RADIO_BUTTON,
-    "draw arcs",                               'a'
+    "Draw arcs",                               'a'
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_RECTANGLE,      GADGET_ID_RECTANGLE,
     &editor.button.draw_rectangle,             GD_TYPE_RADIO_BUTTON,
-    "draw outline rectangles",                 'r'
+    "Draw outline rectangles",                 'r'
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_FILLED_BOX,     GADGET_ID_FILLED_BOX,
     &editor.button.draw_filled_box,            GD_TYPE_RADIO_BUTTON,
-    "draw filled rectangles",                  'R'
+    "Draw filled rectangles",                  'R'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ROTATE_UP,           GADGET_ID_WRAP_UP,
     &editor.button.rotate_up,                  GD_TYPE_NORMAL_BUTTON,
-    "wrap (rotate) level up",                  0
+    "Wrap (rotate) level up",                  0
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_TEXT,           GADGET_ID_TEXT,
     &editor.button.draw_text,                  GD_TYPE_RADIO_BUTTON,
-    "enter text elements",                     't'
+    "Enter text elements",                     't'
   },
   {
     IMG_GFX_EDITOR_BUTTON_FLOOD_FILL,          GADGET_ID_FLOOD_FILL,
     &editor.button.flood_fill,                 GD_TYPE_RADIO_BUTTON,
-    "flood fill",                              'f'
+    "Flood fill",                              'f'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ROTATE_LEFT,         GADGET_ID_WRAP_LEFT,
     &editor.button.rotate_left,                        GD_TYPE_NORMAL_BUTTON,
-    "wrap (rotate) level left",                        0
+    "Wrap (rotate) level left",                        0
   },
   {
     IMG_GFX_EDITOR_BUTTON_ZOOM_LEVEL,          GADGET_ID_ZOOM,
     &editor.button.zoom_level,                 GD_TYPE_NORMAL_BUTTON,
-    "zoom level tile size",                    '+'
+    "Zoom level tile size",                    '+'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ROTATE_RIGHT,                GADGET_ID_WRAP_RIGHT,
     &editor.button.rotate_right,               GD_TYPE_NORMAL_BUTTON,
-    "wrap (rotate) level right",               0
+    "Wrap (rotate) level right",               0
   },
   {
     IMG_GFX_EDITOR_BUTTON_DRAW_RANDOM,         GADGET_ID_RANDOM_PLACEMENT,
     &editor.button.draw_random,                        GD_TYPE_NORMAL_BUTTON,
-    "random element placement",                        0
+    "Random element placement",                        0
   },
   {
     IMG_GFX_EDITOR_BUTTON_GRAB_BRUSH,          GADGET_ID_GRAB_BRUSH,
     &editor.button.grab_brush,                 GD_TYPE_RADIO_BUTTON,
-    "grab brush",                              'b'
+    "Grab brush",                              'b'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ROTATE_DOWN,         GADGET_ID_WRAP_DOWN,
     &editor.button.rotate_down,                        GD_TYPE_NORMAL_BUTTON,
-    "wrap (rotate) level down",                        0
+    "Wrap (rotate) level down",                        0
   },
   {
     IMG_GFX_EDITOR_BUTTON_PICK_ELEMENT,                GADGET_ID_PICK_ELEMENT,
     &editor.button.pick_element,               GD_TYPE_RADIO_BUTTON,
-    "pick drawing element",                    ','
+    "Pick drawing element",                    ','
   },
 
   // ---------- level control buttons -----------------------------------------
@@ -1259,32 +1562,32 @@ static struct
   {
     IMG_GFX_EDITOR_BUTTON_UNDO,                        GADGET_ID_UNDO,
     &editor.button.undo,                       GD_TYPE_NORMAL_BUTTON,
-    "undo/redo last operation",                        'u'
+    "Undo/redo last operation",                        'u'
   },
   {
-    IMG_GFX_EDITOR_BUTTON_CONF,                        GADGET_ID_INFO,
+    IMG_GFX_EDITOR_BUTTON_CONF,                        GADGET_ID_CONF,
     &editor.button.conf,                       GD_TYPE_NORMAL_BUTTON,
-    "properties of level",                     'I'
+    "Level and editor settings",               'I'
   },
   {
     IMG_GFX_EDITOR_BUTTON_SAVE,                        GADGET_ID_SAVE,
     &editor.button.save,                       GD_TYPE_NORMAL_BUTTON,
-    "save level",                              'S'
+    "Save level",                              'S'
   },
   {
     IMG_GFX_EDITOR_BUTTON_CLEAR,               GADGET_ID_CLEAR,
     &editor.button.clear,                      GD_TYPE_NORMAL_BUTTON,
-    "clear level",                             'C'
+    "Clear level",                             'C'
   },
   {
     IMG_GFX_EDITOR_BUTTON_TEST,                        GADGET_ID_TEST,
     &editor.button.test,                       GD_TYPE_NORMAL_BUTTON,
-    "test level",                              'T'
+    "Test level",                              'T'
   },
   {
     IMG_GFX_EDITOR_BUTTON_EXIT,                        GADGET_ID_EXIT,
     &editor.button.exit,                       GD_TYPE_NORMAL_BUTTON,
-    "exit level editor",                       'E'
+    "Exit level editor",                       'E'
   },
 
   // ---------- CE and GE control buttons -------------------------------------
@@ -1292,27 +1595,27 @@ static struct
   {
     IMG_GFX_EDITOR_BUTTON_CE_COPY_FROM,                GADGET_ID_CUSTOM_COPY_FROM,
     &editor.button.ce_copy_from,               GD_TYPE_RADIO_BUTTON,
-    "copy settings from other element",                0
+    "Copy settings from other element",                0
   },
   {
     IMG_GFX_EDITOR_BUTTON_CE_COPY_TO,          GADGET_ID_CUSTOM_COPY_TO,
     &editor.button.ce_copy_to,                 GD_TYPE_RADIO_BUTTON,
-    "copy settings to other element",          0
+    "Copy settings to other element",          0
   },
   {
     IMG_GFX_EDITOR_BUTTON_CE_SWAP,             GADGET_ID_CUSTOM_EXCHANGE,
     &editor.button.ce_swap,                    GD_TYPE_RADIO_BUTTON,
-    "exchange element with other element",     0
+    "Exchange element with other element",     0
   },
   {
     IMG_GFX_EDITOR_BUTTON_CE_COPY,             GADGET_ID_CUSTOM_COPY,
     &editor.button.ce_copy,                    GD_TYPE_NORMAL_BUTTON,
-    "copy settings from this element",         0
+    "Copy settings from this element",         0
   },
   {
     IMG_GFX_EDITOR_BUTTON_CE_PASTE,            GADGET_ID_CUSTOM_PASTE,
     &editor.button.ce_paste,                   GD_TYPE_NORMAL_BUTTON,
-    "paste settings to this element",          0
+    "Paste settings to this element",          0
   },
 
   // ---------- palette control buttons ---------------------------------------
@@ -1320,27 +1623,27 @@ static struct
   {
     IMG_GFX_EDITOR_BUTTON_PROPERTIES,          GADGET_ID_PROPERTIES,
     &editor.button.properties,                 GD_TYPE_NORMAL_BUTTON,
-    "properties of drawing element",           'p'
+    "Properties of drawing element",           'p'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ELEMENT_LEFT,                GADGET_ID_ELEMENT_LEFT,
     &editor.button.element_left,               GD_TYPE_NORMAL_BUTTON,
-    "properties of drawing element 1",         '1'
+    "Properties of drawing element 1",         '1'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ELEMENT_MIDDLE,      GADGET_ID_ELEMENT_MIDDLE,
     &editor.button.element_middle,             GD_TYPE_NORMAL_BUTTON,
-    "properties of drawing element 2",         '2'
+    "Properties of drawing element 2",         '2'
   },
   {
     IMG_GFX_EDITOR_BUTTON_ELEMENT_RIGHT,       GADGET_ID_ELEMENT_RIGHT,
     &editor.button.element_right,              GD_TYPE_NORMAL_BUTTON,
-    "properties of drawing element 3",         '3'
+    "Properties of drawing element 3",         '3'
   },
   {
     IMG_GFX_EDITOR_BUTTON_PALETTE,             GADGET_ID_PALETTE,
     &editor.button.palette,                    GD_TYPE_NORMAL_BUTTON,
-    "show list of elements",                   'e'
+    "Show list of elements",                   'e'
   }
 };
 
@@ -1362,8 +1665,28 @@ static boolean levelset_use_levelset_artwork = FALSE;
 static boolean levelset_copy_level_template = FALSE;
 static int levelset_save_mode = LEVELSET_SAVE_MODE_UPDATE;
 
+#define MAX_BD_COLORS                  7
+#define MAX_BD_COLOR_TEXT_LEN          10
+
+static boolean bd_color_type_changed = FALSE;
+static int bd_color_type_default = GD_COLOR_TYPE_RGB;
+static int bd_color_c64[MAX_BD_COLORS];
+static char bd_color_text[MAX_BD_COLORS][MAX_BD_COLOR_TEXT_LEN + 1];
+static int bd_color_default[MAX_BD_COLORS];
+static int *bd_color[MAX_BD_COLORS] =
+{
+  &level.bd_color_b,
+  &level.bd_color_0,
+  &level.bd_color_1,
+  &level.bd_color_2,
+  &level.bd_color_3,
+  &level.bd_color_4,
+  &level.bd_color_5,
+};
+
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int min_value, max_value;
   int gadget_id_down, gadget_id_up;
@@ -1376,1070 +1699,1306 @@ static struct
   // ---------- current level number ------------------------------------------
 
   {
+    ED_COUNTER_ID_SELECT_LEVEL,
     -1, -1,    // these values are not constant, but can change at runtime
-    1,                                 100,
-    GADGET_ID_SELECT_LEVEL_DOWN,       GADGET_ID_SELECT_LEVEL_UP,
-    GADGET_ID_SELECT_LEVEL_TEXT,       GADGET_ID_NONE,
+    1,                                         100,
+    GADGET_ID_SELECT_LEVEL_DOWN,               GADGET_ID_SELECT_LEVEL_UP,
+    GADGET_ID_SELECT_LEVEL_TEXT,               GADGET_ID_NONE,
     &level_nr,
-    NULL,                              NULL, NULL
+    NULL,                                      NULL, NULL
   },
 
   // ---------- level and editor settings -------------------------------------
 
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(4),
-    MIN_LEV_FIELDX,                    MAX_LEV_FIELDX,
-    GADGET_ID_LEVEL_XSIZE_DOWN,                GADGET_ID_LEVEL_XSIZE_UP,
-    GADGET_ID_LEVEL_XSIZE_TEXT,                GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_XSIZE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(4),
+    MIN_LEV_FIELDX,                            MAX_LEV_FIELDX,
+    GADGET_ID_LEVEL_XSIZE_DOWN,                        GADGET_ID_LEVEL_XSIZE_UP,
+    GADGET_ID_LEVEL_XSIZE_TEXT,                        GADGET_ID_NONE,
     &level.fieldx,
-    "playfield size:",                 NULL, "width",
+    "Playfield size:",                         NULL, "Width",
   },
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(4),
-    MIN_LEV_FIELDY,                    MAX_LEV_FIELDY,
-    GADGET_ID_LEVEL_YSIZE_DOWN,                GADGET_ID_LEVEL_YSIZE_UP,
-    GADGET_ID_LEVEL_YSIZE_TEXT,                GADGET_ID_LEVEL_XSIZE_UP,
+    ED_COUNTER_ID_LEVEL_YSIZE,
+    -1,                                                ED_LEVEL_SETTINGS_YPOS(4),
+    MIN_LEV_FIELDY,                            MAX_LEV_FIELDY,
+    GADGET_ID_LEVEL_YSIZE_DOWN,                        GADGET_ID_LEVEL_YSIZE_UP,
+    GADGET_ID_LEVEL_YSIZE_TEXT,                        GADGET_ID_LEVEL_XSIZE_UP,
     &level.fieldy,
-    NULL,                              " ", "height",
+    NULL,                                      " ", "Height",
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(5),
-    0,                                 999,
-    GADGET_ID_LEVEL_GEMSLIMIT_DOWN,    GADGET_ID_LEVEL_GEMSLIMIT_UP,
-    GADGET_ID_LEVEL_GEMSLIMIT_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_GEMSLIMIT,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(5),
+    0,                                         999,
+    GADGET_ID_LEVEL_GEMSLIMIT_DOWN,            GADGET_ID_LEVEL_GEMSLIMIT_UP,
+    GADGET_ID_LEVEL_GEMSLIMIT_TEXT,            GADGET_ID_NONE,
     &level.gems_needed,
-    NULL,                              "number of gems to collect:", NULL
+    NULL,                                      "Number of gems to collect:", NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(8),
-    0,                                 9999,
-    GADGET_ID_LEVEL_TIMELIMIT_DOWN,    GADGET_ID_LEVEL_TIMELIMIT_UP,
-    GADGET_ID_LEVEL_TIMELIMIT_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_TIMELIMIT,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(8),
+    0,                                         9999,
+    GADGET_ID_LEVEL_TIMELIMIT_DOWN,            GADGET_ID_LEVEL_TIMELIMIT_UP,
+    GADGET_ID_LEVEL_TIMELIMIT_TEXT,            GADGET_ID_NONE,
     &level.time,
-    "time or step limit to solve level:", NULL, NULL
+    "Time or step limit to solve level:",      NULL, NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(10),
-    0,                                 999,
-    GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
-    GADGET_ID_LEVEL_TIMESCORE_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_TIMESCORE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(10),
+    0,                                         999,
+    GADGET_ID_LEVEL_TIMESCORE_DOWN,            GADGET_ID_LEVEL_TIMESCORE_UP,
+    GADGET_ID_LEVEL_TIMESCORE_TEXT,            GADGET_ID_NONE,
     &level.score[SC_TIME_BONUS],
-    "score for time or steps left:",   NULL, NULL
+    "Score for time or steps left:",           NULL, NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(13),
-    0,                                 9999,
-    GADGET_ID_LEVEL_RANDOM_SEED_DOWN,  GADGET_ID_LEVEL_RANDOM_SEED_UP,
-    GADGET_ID_LEVEL_RANDOM_SEED_TEXT,  GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_RANDOM_SEED,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(13),
+    0,                                         9999,
+    GADGET_ID_LEVEL_RANDOM_SEED_DOWN,          GADGET_ID_LEVEL_RANDOM_SEED_UP,
+    GADGET_ID_LEVEL_RANDOM_SEED_TEXT,          GADGET_ID_NONE,
     &level.random_seed,
-    NULL,                              "random seed:", "(0 => random)"
+    NULL,                                      "Random seed:", "(0 => random)"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(4),
-    1,                                 MAX_LEVELS,
-    GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,        GADGET_ID_LEVELSET_NUM_LEVELS_UP,
-    GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,        GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVELSET_NUM_LEVELS,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(4),
+    1,                                         MAX_LEVELS,
+    GADGET_ID_LEVELSET_NUM_LEVELS_DOWN,                GADGET_ID_LEVELSET_NUM_LEVELS_UP,
+    GADGET_ID_LEVELSET_NUM_LEVELS_TEXT,                GADGET_ID_NONE,
     &levelset_num_levels,
-    "number of levels:",               NULL, NULL,
+    "Number of levels:",                       NULL, NULL,
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(0),
-    1,                                 100,
-    GADGET_ID_LEVEL_RANDOM_DOWN,       GADGET_ID_LEVEL_RANDOM_UP,
-    GADGET_ID_LEVEL_RANDOM_TEXT,       GADGET_ID_NONE,
+    ED_COUNTER_ID_LEVEL_RANDOM,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(0),
+    1,                                         100,
+    GADGET_ID_LEVEL_RANDOM_DOWN,               GADGET_ID_LEVEL_RANDOM_UP,
+    GADGET_ID_LEVEL_RANDOM_TEXT,               GADGET_ID_NONE,
     &random_placement_value,
-    "random element placement:",       NULL, "in"
+    "Random element placement:",               NULL, "in"
+  },
+  {
+    ED_COUNTER_ID_BD_CYCLE_DELAY_MS,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(3),
+    50,                                                500,
+    GADGET_ID_BD_CYCLE_DELAY_MS_DOWN,          GADGET_ID_BD_CYCLE_DELAY_MS_UP,
+    GADGET_ID_BD_CYCLE_DELAY_MS_TEXT,          GADGET_ID_NONE,
+    &level.bd_cycle_delay_ms,
+    NULL,                                      NULL, "Game cycle delay (ms)"
+  },
+  {
+    ED_COUNTER_ID_BD_CYCLE_DELAY_C64,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(3),
+    0,                                         32,
+    GADGET_ID_BD_CYCLE_DELAY_C64_DOWN,         GADGET_ID_BD_CYCLE_DELAY_C64_UP,
+    GADGET_ID_BD_CYCLE_DELAY_C64_TEXT,         GADGET_ID_NONE,
+    &level.bd_cycle_delay_c64,
+    NULL,                                      NULL, "Game cycle delay (C64-style)"
+  },
+  {
+    ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(4),
+    1,                                         40,
+    GADGET_ID_BD_HATCHING_DELAY_CYCLES_DOWN,   GADGET_ID_BD_HATCHING_DELAY_CYCLES_UP,
+    GADGET_ID_BD_HATCHING_DELAY_CYCLES_TEXT,   GADGET_ID_NONE,
+    &level.bd_hatching_delay_cycles,
+    NULL,                                      NULL, "Hatching delay (cycles)"
+  },
+  {
+    ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(4),
+    1,                                         40,
+    GADGET_ID_BD_HATCHING_DELAY_SECONDS_DOWN,  GADGET_ID_BD_HATCHING_DELAY_SECONDS_UP,
+    GADGET_ID_BD_HATCHING_DELAY_SECONDS_TEXT,  GADGET_ID_NONE,
+    &level.bd_hatching_delay_seconds,
+    NULL,                                      NULL, "Hatching delay (seconds)"
   },
 
   // ---------- element settings: configure (various elements) ----------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_ELEMENT_VALUE1_DOWN,     GADGET_ID_ELEMENT_VALUE1_UP,
-    GADGET_ID_ELEMENT_VALUE1_TEXT,     GADGET_ID_NONE,
-    NULL,                              // will be set when used
-    NULL,                              NULL, NULL
+    ED_COUNTER_ID_BD_PUSHING_PROB,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    0,                                         100,
+    GADGET_ID_BD_PUSHING_PROB_DOWN,            GADGET_ID_BD_PUSHING_PROB_UP,
+    GADGET_ID_BD_PUSHING_PROB_TEXT,            GADGET_ID_NONE,
+    &level.bd_pushing_prob,
+    NULL,                                      NULL, "Push probability"
+  },
+  {
+    ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    0,                                         100,
+    GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_DOWN, GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_UP,
+    GADGET_ID_BD_PUSHING_PROB_WITH_SWEET_TEXT, GADGET_ID_NONE,
+    &level.bd_pushing_prob_with_sweet,
+    NULL,                                      NULL, "Push probability with sweet"
+  },
+  {
+    ED_COUNTER_ID_ELEMENT_VALUE1,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    MIN_SCORE,                                 MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE1_DOWN,             GADGET_ID_ELEMENT_VALUE1_UP,
+    GADGET_ID_ELEMENT_VALUE1_TEXT,             GADGET_ID_NONE,
+    NULL,                                      // will be set when used
+    NULL,                                      NULL, NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_ELEMENT_VALUE2_DOWN,     GADGET_ID_ELEMENT_VALUE2_UP,
-    GADGET_ID_ELEMENT_VALUE2_TEXT,     GADGET_ID_NONE,
-    NULL,                              // will be set when used
-    NULL,                              NULL, NULL
+    ED_COUNTER_ID_ELEMENT_VALUE2,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    MIN_SCORE,                                 MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE2_DOWN,             GADGET_ID_ELEMENT_VALUE2_UP,
+    GADGET_ID_ELEMENT_VALUE2_TEXT,             GADGET_ID_NONE,
+    NULL,                                      // will be set when used
+    NULL,                                      NULL, NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_ELEMENT_VALUE3_DOWN,     GADGET_ID_ELEMENT_VALUE3_UP,
-    GADGET_ID_ELEMENT_VALUE3_TEXT,     GADGET_ID_NONE,
-    NULL,                              // will be set when used
-    NULL,                              NULL, NULL
+    ED_COUNTER_ID_ELEMENT_VALUE3,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    MIN_SCORE,                                 MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE3_DOWN,             GADGET_ID_ELEMENT_VALUE3_UP,
+    GADGET_ID_ELEMENT_VALUE3_TEXT,             GADGET_ID_NONE,
+    NULL,                                      // will be set when used
+    NULL,                                      NULL, NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_ELEMENT_VALUE4_DOWN,     GADGET_ID_ELEMENT_VALUE4_UP,
-    GADGET_ID_ELEMENT_VALUE4_TEXT,     GADGET_ID_NONE,
-    NULL,                              // will be set when used
-    NULL,                              NULL, NULL
+    ED_COUNTER_ID_ELEMENT_VALUE4,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_SCORE,                                 MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE4_DOWN,             GADGET_ID_ELEMENT_VALUE4_UP,
+    GADGET_ID_ELEMENT_VALUE4_TEXT,             GADGET_ID_NONE,
+    NULL,                                      // will be set when used
+    NULL,                                      NULL, NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
-    GADGET_ID_YAMYAM_CONTENT_DOWN,     GADGET_ID_YAMYAM_CONTENT_UP,
-    GADGET_ID_YAMYAM_CONTENT_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_YAMYAM_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_ELEMENT_CONTENTS,                      MAX_ELEMENT_CONTENTS,
+    GADGET_ID_YAMYAM_CONTENT_DOWN,             GADGET_ID_YAMYAM_CONTENT_UP,
+    GADGET_ID_YAMYAM_CONTENT_TEXT,             GADGET_ID_NONE,
     &level.num_yamyam_contents,
-    NULL,                              NULL, "number of content areas"
+    NULL,                                      NULL, "Number of content areas"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
-    GADGET_ID_BALL_CONTENT_DOWN,       GADGET_ID_BALL_CONTENT_UP,
-    GADGET_ID_BALL_CONTENT_TEXT,       GADGET_ID_NONE,
+    ED_COUNTER_ID_BALL_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    MIN_ELEMENT_CONTENTS,                      MAX_ELEMENT_CONTENTS,
+    GADGET_ID_BALL_CONTENT_DOWN,               GADGET_ID_BALL_CONTENT_UP,
+    GADGET_ID_BALL_CONTENT_TEXT,               GADGET_ID_NONE,
     &level.num_ball_contents,
-    NULL,                              NULL, "number of content areas"
+    NULL,                                      NULL, "Number of content areas"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    MIN_ANDROID_ELEMENTS,              MAX_ANDROID_ELEMENTS,
-    GADGET_ID_ANDROID_CONTENT_DOWN,    GADGET_ID_ANDROID_CONTENT_UP,
-    GADGET_ID_ANDROID_CONTENT_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_ANDROID_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    MIN_ANDROID_ELEMENTS,                      MAX_ANDROID_ELEMENTS,
+    GADGET_ID_ANDROID_CONTENT_DOWN,            GADGET_ID_ANDROID_CONTENT_UP,
+    GADGET_ID_ANDROID_CONTENT_TEXT,            GADGET_ID_NONE,
     &level.num_android_clone_elements,
-    NULL,                              NULL, "number of clonable elements"
+    NULL,                                      NULL, "Number of clonable elements"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    MIN_ENVELOPE_XSIZE,                        MAX_ENVELOPE_XSIZE,
-    GADGET_ID_ENVELOPE_XSIZE_DOWN,     GADGET_ID_ENVELOPE_XSIZE_UP,
-    GADGET_ID_ENVELOPE_XSIZE_TEXT,     GADGET_ID_NONE,
-    NULL,                              // will be set when used
-    NULL,                              NULL, "width",
+    ED_COUNTER_ID_ENVELOPE_XSIZE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    MIN_ENVELOPE_XSIZE,                                MAX_ENVELOPE_XSIZE,
+    GADGET_ID_ENVELOPE_XSIZE_DOWN,             GADGET_ID_ENVELOPE_XSIZE_UP,
+    GADGET_ID_ENVELOPE_XSIZE_TEXT,             GADGET_ID_NONE,
+    NULL,                                      // will be set when used
+    NULL,                                      NULL, "Width",
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(0),
-    MIN_ENVELOPE_YSIZE,                        MAX_ENVELOPE_YSIZE,
-    GADGET_ID_ENVELOPE_YSIZE_DOWN,     GADGET_ID_ENVELOPE_YSIZE_UP,
-    GADGET_ID_ENVELOPE_YSIZE_TEXT,     GADGET_ID_ENVELOPE_XSIZE_UP,
-    NULL,                              // will be set when used
-    NULL,                              " ", "height",
+    ED_COUNTER_ID_ENVELOPE_YSIZE,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(0),
+    MIN_ENVELOPE_YSIZE,                                MAX_ENVELOPE_YSIZE,
+    GADGET_ID_ENVELOPE_YSIZE_DOWN,             GADGET_ID_ENVELOPE_YSIZE_UP,
+    GADGET_ID_ENVELOPE_YSIZE_TEXT,             GADGET_ID_ENVELOPE_XSIZE_UP,
+    NULL,                                      // will be set when used
+    NULL,                                      " ", "Height",
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    MIN_INITIAL_INVENTORY_SIZE,                MAX_INITIAL_INVENTORY_SIZE,
-    GADGET_ID_INVENTORY_SIZE_DOWN,     GADGET_ID_INVENTORY_SIZE_UP,
-    GADGET_ID_INVENTORY_SIZE_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_INVENTORY_SIZE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    MIN_INITIAL_INVENTORY_SIZE,                        MAX_INITIAL_INVENTORY_SIZE,
+    GADGET_ID_INVENTORY_SIZE_DOWN,             GADGET_ID_INVENTORY_SIZE_UP,
+    GADGET_ID_INVENTORY_SIZE_TEXT,             GADGET_ID_NONE,
     &level.initial_inventory_size[0],
-    NULL,                              NULL, "number of inventory elements"
+    NULL,                                      NULL, "Number of inventory elements"
+  },
+  {
+    ED_COUNTER_ID_MM_BALL_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_ELEMENTS_IN_GROUP,                     MAX_MM_BALL_CONTENTS,
+    GADGET_ID_MM_BALL_CONTENT_DOWN,            GADGET_ID_MM_BALL_CONTENT_UP,
+    GADGET_ID_MM_BALL_CONTENT_TEXT,            GADGET_ID_NONE,
+    &level.num_mm_ball_contents,
+    NULL,                                      NULL, "Number of content elements"
   },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(5),
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_CUSTOM_SCORE_DOWN,       GADGET_ID_CUSTOM_SCORE_UP,
-    GADGET_ID_CUSTOM_SCORE_TEXT,       GADGET_ID_NONE,
+    ED_COUNTER_ID_CUSTOM_SCORE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(5),
+    MIN_SCORE,                                 MAX_SCORE,
+    GADGET_ID_CUSTOM_SCORE_DOWN,               GADGET_ID_CUSTOM_SCORE_UP,
+    GADGET_ID_CUSTOM_SCORE_TEXT,               GADGET_ID_NONE,
     &custom_element.collect_score_initial,
-    NULL,                              "CE score", " "
+    NULL,                                      "CE score", " "
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(5),
-    MIN_COLLECT_COUNT,                 MAX_COLLECT_COUNT,
-    GADGET_ID_CUSTOM_GEMCOUNT_DOWN,    GADGET_ID_CUSTOM_GEMCOUNT_UP,
-    GADGET_ID_CUSTOM_GEMCOUNT_TEXT,    GADGET_ID_CUSTOM_SCORE_UP,
+    ED_COUNTER_ID_CUSTOM_GEMCOUNT,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(5),
+    MIN_COLLECT_COUNT,                         MAX_COLLECT_COUNT,
+    GADGET_ID_CUSTOM_GEMCOUNT_DOWN,            GADGET_ID_CUSTOM_GEMCOUNT_UP,
+    GADGET_ID_CUSTOM_GEMCOUNT_TEXT,            GADGET_ID_CUSTOM_SCORE_UP,
     &custom_element.collect_count_initial,
-    NULL,                              "CE count", NULL
+    NULL,                                      "CE count", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
-    0,                                 9999,
-    GADGET_ID_CUSTOM_VALUE_FIX_DOWN,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
-    GADGET_ID_CUSTOM_VALUE_FIX_TEXT,   GADGET_ID_NONE,
+    ED_COUNTER_ID_CUSTOM_VALUE_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(10),
+    0,                                         9999,
+    GADGET_ID_CUSTOM_VALUE_FIX_DOWN,           GADGET_ID_CUSTOM_VALUE_FIX_UP,
+    GADGET_ID_CUSTOM_VALUE_FIX_TEXT,           GADGET_ID_NONE,
     &custom_element.ce_value_fixed_initial,
-    NULL,                              "CE value", NULL
+    NULL,                                      "CE value", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
-    0,                                 9999,
-    GADGET_ID_CUSTOM_VALUE_RND_DOWN,   GADGET_ID_CUSTOM_VALUE_RND_UP,
-    GADGET_ID_CUSTOM_VALUE_RND_TEXT,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
+    ED_COUNTER_ID_CUSTOM_VALUE_RND,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(10),
+    0,                                         9999,
+    GADGET_ID_CUSTOM_VALUE_RND_DOWN,           GADGET_ID_CUSTOM_VALUE_RND_UP,
+    GADGET_ID_CUSTOM_VALUE_RND_TEXT,           GADGET_ID_CUSTOM_VALUE_FIX_UP,
     &custom_element.ce_value_random_initial,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
-    0,                                 999,
-    GADGET_ID_PUSH_DELAY_FIX_DOWN,     GADGET_ID_PUSH_DELAY_FIX_UP,
-    GADGET_ID_PUSH_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_PUSH_DELAY_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                         999,
+    GADGET_ID_PUSH_DELAY_FIX_DOWN,             GADGET_ID_PUSH_DELAY_FIX_UP,
+    GADGET_ID_PUSH_DELAY_FIX_TEXT,             GADGET_ID_NONE,
     &custom_element.push_delay_fixed,
-    NULL,                              "push delay", NULL
+    NULL,                                      "Push delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
-    0,                                 999,
-    GADGET_ID_PUSH_DELAY_RND_DOWN,     GADGET_ID_PUSH_DELAY_RND_UP,
-    GADGET_ID_PUSH_DELAY_RND_TEXT,     GADGET_ID_PUSH_DELAY_FIX_UP,
+    ED_COUNTER_ID_PUSH_DELAY_RND,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                         999,
+    GADGET_ID_PUSH_DELAY_RND_DOWN,             GADGET_ID_PUSH_DELAY_RND_UP,
+    GADGET_ID_PUSH_DELAY_RND_TEXT,             GADGET_ID_PUSH_DELAY_FIX_UP,
     &custom_element.push_delay_random,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(7),
-    0,                                 999,
-    GADGET_ID_DROP_DELAY_FIX_DOWN,     GADGET_ID_DROP_DELAY_FIX_UP,
-    GADGET_ID_DROP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_DROP_DELAY_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(7),
+    0,                                         999,
+    GADGET_ID_DROP_DELAY_FIX_DOWN,             GADGET_ID_DROP_DELAY_FIX_UP,
+    GADGET_ID_DROP_DELAY_FIX_TEXT,             GADGET_ID_NONE,
     &custom_element.drop_delay_fixed,
-    NULL,                              "drop delay", NULL
+    NULL,                                      "Drop delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
-    0,                                 999,
-    GADGET_ID_DROP_DELAY_RND_DOWN,     GADGET_ID_DROP_DELAY_RND_UP,
-    GADGET_ID_DROP_DELAY_RND_TEXT,     GADGET_ID_DROP_DELAY_FIX_UP,
+    ED_COUNTER_ID_DROP_DELAY_RND,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(7),
+    0,                                         999,
+    GADGET_ID_DROP_DELAY_RND_DOWN,             GADGET_ID_DROP_DELAY_RND_UP,
+    GADGET_ID_DROP_DELAY_RND_TEXT,             GADGET_ID_DROP_DELAY_FIX_UP,
     &custom_element.drop_delay_random,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
 
   // ---------- element settings: configure 2 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(5),
-    0,                                 999,
-    GADGET_ID_MOVE_DELAY_FIX_DOWN,     GADGET_ID_MOVE_DELAY_FIX_UP,
-    GADGET_ID_MOVE_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_MOVE_DELAY_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(5),
+    0,                                         999,
+    GADGET_ID_MOVE_DELAY_FIX_DOWN,             GADGET_ID_MOVE_DELAY_FIX_UP,
+    GADGET_ID_MOVE_DELAY_FIX_TEXT,             GADGET_ID_NONE,
     &custom_element.move_delay_fixed,
-    NULL,                              "move delay", NULL
+    NULL,                                      "Move delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(5),
-    0,                                 999,
-    GADGET_ID_MOVE_DELAY_RND_DOWN,     GADGET_ID_MOVE_DELAY_RND_UP,
-    GADGET_ID_MOVE_DELAY_RND_TEXT,     GADGET_ID_MOVE_DELAY_FIX_UP,
+    ED_COUNTER_ID_MOVE_DELAY_RND,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(5),
+    0,                                         999,
+    GADGET_ID_MOVE_DELAY_RND_DOWN,             GADGET_ID_MOVE_DELAY_RND_UP,
+    GADGET_ID_MOVE_DELAY_RND_TEXT,             GADGET_ID_MOVE_DELAY_FIX_UP,
     &custom_element.move_delay_random,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
-    0,                                 999,
-    GADGET_ID_STEP_DELAY_FIX_DOWN,     GADGET_ID_STEP_DELAY_FIX_UP,
-    GADGET_ID_STEP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_STEP_DELAY_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                         999,
+    GADGET_ID_STEP_DELAY_FIX_DOWN,             GADGET_ID_STEP_DELAY_FIX_UP,
+    GADGET_ID_STEP_DELAY_FIX_TEXT,             GADGET_ID_NONE,
     &custom_element.step_delay_fixed,
-    NULL,                              "step delay", NULL
+    NULL,                                      "Step delay", NULL
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
-    0,                                 999,
-    GADGET_ID_STEP_DELAY_RND_DOWN,     GADGET_ID_STEP_DELAY_RND_UP,
-    GADGET_ID_STEP_DELAY_RND_TEXT,     GADGET_ID_STEP_DELAY_FIX_UP,
+    ED_COUNTER_ID_STEP_DELAY_RND,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                         999,
+    GADGET_ID_STEP_DELAY_RND_DOWN,             GADGET_ID_STEP_DELAY_RND_UP,
+    GADGET_ID_STEP_DELAY_RND_TEXT,             GADGET_ID_STEP_DELAY_FIX_UP,
     &custom_element.step_delay_random,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
-    0,                                 999,
-    GADGET_ID_EXPLOSION_DELAY_DOWN,    GADGET_ID_EXPLOSION_DELAY_UP,
-    GADGET_ID_EXPLOSION_DELAY_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_EXPLOSION_DELAY,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(13),
+    0,                                         999,
+    GADGET_ID_EXPLOSION_DELAY_DOWN,            GADGET_ID_EXPLOSION_DELAY_UP,
+    GADGET_ID_EXPLOSION_DELAY_TEXT,            GADGET_ID_NONE,
     &custom_element.explosion_delay,
-    NULL,                              "explosion delay", NULL
+    NULL,                                      "Explosion delay", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(14),
-    0,                                 999,
-    GADGET_ID_IGNITION_DELAY_DOWN,     GADGET_ID_IGNITION_DELAY_UP,
-    GADGET_ID_IGNITION_DELAY_TEXT,     GADGET_ID_NONE,
+    ED_COUNTER_ID_IGNITION_DELAY,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(14),
+    0,                                         999,
+    GADGET_ID_IGNITION_DELAY_DOWN,             GADGET_ID_IGNITION_DELAY_UP,
+    GADGET_ID_IGNITION_DELAY_TEXT,             GADGET_ID_NONE,
     &custom_element.ignition_delay,
-    NULL,                              "ignition delay", "(by fire)"
+    NULL,                                      "Ignition delay", "(by fire)"
   },
 
   // ---------- element settings: configure (group elements) ------------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    MIN_ELEMENTS_IN_GROUP,             MAX_ELEMENTS_IN_GROUP,
-    GADGET_ID_GROUP_CONTENT_DOWN,      GADGET_ID_GROUP_CONTENT_UP,
-    GADGET_ID_GROUP_CONTENT_TEXT,      GADGET_ID_NONE,
+    ED_COUNTER_ID_GROUP_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_ELEMENTS_IN_GROUP,                     MAX_ELEMENTS_IN_GROUP,
+    GADGET_ID_GROUP_CONTENT_DOWN,              GADGET_ID_GROUP_CONTENT_UP,
+    GADGET_ID_GROUP_CONTENT_TEXT,              GADGET_ID_NONE,
     &group_element_info.num_elements,
-    NULL,                              NULL, "number of elements in group"
+    NULL,                                      NULL, "Number of elements in group"
   },
 
   // ---------- element settings: advanced (custom elements) ------------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(2),
-    0,                                 999,
-    GADGET_ID_CHANGE_DELAY_FIX_DOWN,   GADGET_ID_CHANGE_DELAY_FIX_UP,
-    GADGET_ID_CHANGE_DELAY_FIX_TEXT,   GADGET_ID_NONE,
+    ED_COUNTER_ID_CHANGE_DELAY_FIX,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(2),
+    0,                                         999,
+    GADGET_ID_CHANGE_DELAY_FIX_DOWN,           GADGET_ID_CHANGE_DELAY_FIX_UP,
+    GADGET_ID_CHANGE_DELAY_FIX_TEXT,           GADGET_ID_NONE,
     &custom_element_change.delay_fixed,
-    NULL,                              "CE delay", NULL,
+    NULL,                                      "CE delay", NULL,
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
-    0,                                 999,
-    GADGET_ID_CHANGE_DELAY_RND_DOWN,   GADGET_ID_CHANGE_DELAY_RND_UP,
-    GADGET_ID_CHANGE_DELAY_RND_TEXT,   GADGET_ID_CHANGE_DELAY_FIX_UP,
+    ED_COUNTER_ID_CHANGE_DELAY_RND,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(2),
+    0,                                         999,
+    GADGET_ID_CHANGE_DELAY_RND_DOWN,           GADGET_ID_CHANGE_DELAY_RND_UP,
+    GADGET_ID_CHANGE_DELAY_RND_TEXT,           GADGET_ID_CHANGE_DELAY_FIX_UP,
     &custom_element_change.delay_random,
-    NULL,                              "+random", NULL
+    NULL,                                      "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(3),       ED_ELEMENT_SETTINGS_YPOS(12),
-    0,                                 100,
-    GADGET_ID_CHANGE_CONT_RND_DOWN,    GADGET_ID_CHANGE_CONT_RND_UP,
-    GADGET_ID_CHANGE_CONT_RND_TEXT,    GADGET_ID_NONE,
+    ED_COUNTER_ID_CHANGE_CONT_RND,
+    ED_ELEMENT_SETTINGS_XPOS(3),               ED_ELEMENT_SETTINGS_YPOS(12),
+    0,                                         100,
+    GADGET_ID_CHANGE_CONT_RND_DOWN,            GADGET_ID_CHANGE_CONT_RND_UP,
+    GADGET_ID_CHANGE_CONT_RND_TEXT,            GADGET_ID_NONE,
     &custom_element_change.random_percentage,
-    NULL,                              "use random replace:", "%"
+    NULL,                                      "Use random replace:", "%"
   },
 };
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int size;
   char *value;
-  char *text_above, *infotext;
+  char *text_above, *text_left, *text_right, *infotext;
 } textinput_info[ED_NUM_TEXTINPUT] =
 {
+  // ---------- level and editor settings -------------------------------------
+
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(0),
+    ED_TEXTINPUT_ID_LEVEL_NAME,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(0),
     GADGET_ID_LEVEL_NAME,
     MAX_LEVEL_NAME_LEN,
     level.name,
-    "Title:", "Title for this level"
+    "Title:", NULL, NULL,                      "Enter title for this level"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(2),
+    ED_TEXTINPUT_ID_LEVEL_AUTHOR,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(2),
     GADGET_ID_LEVEL_AUTHOR,
     MAX_LEVEL_AUTHOR_LEN,
     level.author,
-    "Author:", "Author for this level"
+    "Author:", NULL, NULL,                     "Enter author for this level"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(0),
+    ED_TEXTINPUT_ID_LEVELSET_NAME,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(0),
     GADGET_ID_LEVELSET_NAME,
     MAX_LEVEL_NAME_LEN,
     levelset_name,
-    "Title:", "Title for this or new level set"
+    "Title:", NULL, NULL,                      "Enter title for this or new level set"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(2),
+    ED_TEXTINPUT_ID_LEVELSET_AUTHOR,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(2),
     GADGET_ID_LEVELSET_AUTHOR,
     MAX_LEVEL_AUTHOR_LEN,
     levelset_author,
-    "Author:", "Author for this or new level set"
+    "Author:", NULL, NULL,                     "Enter author for this or new level set"
+  },
+
+  // ---------- engine settings: colors ---------------------------------------
+
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_B,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(1),
+    GADGET_ID_BD_COLOR_TEXT_B,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[0],
+    NULL, "Border color:      ", NULL,         "Enter border color (not used)"
+  },
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_0,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(2),
+    GADGET_ID_BD_COLOR_TEXT_0,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[1],
+    NULL, "Background color:  ", NULL,         "Enter background color (C64 graphics)"
+  },
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_1,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(3),
+    GADGET_ID_BD_COLOR_TEXT_1,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[2],
+    NULL, "Sand color:        ", NULL,         "Enter sand color (C64 graphics)"
+  },
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_2,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(4),
+    GADGET_ID_BD_COLOR_TEXT_2,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[3],
+    NULL, "Steel wall color:  ", NULL,         "Enter steel wall color (C64 graphics)"
   },
   {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_3,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(5),
+    GADGET_ID_BD_COLOR_TEXT_3,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[4],
+    NULL, "Wall color:        ", NULL,         "Enter wall color (C64 graphics)"
+  },
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_4,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(6),
+    GADGET_ID_BD_COLOR_TEXT_4,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[5],
+    NULL, "Amoeba color:      ", NULL,         "Enter amoeba color (C64 graphics)"
+  },
+  {
+    ED_TEXTINPUT_ID_BD_COLOR_TEXT_5,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(7),
+    GADGET_ID_BD_COLOR_TEXT_5,
+    MAX_BD_COLOR_TEXT_LEN,
+    bd_color_text[6],
+    NULL, "Slime color:       ", NULL,         "Enter slime color (C64 graphics)"
+  },
+
+  // ---------- element settings: configure (several elements) ----------------
+
+  {
+    ED_TEXTINPUT_ID_ELEMENT_NAME,
     -1, -1,    // these values are not constant, but can change at runtime
     GADGET_ID_ELEMENT_NAME,
-    MAX_ELEMENT_NAME_LEN - 2,          // currently 2 chars less editable
+    MAX_ELEMENT_NAME_LEN - 2,                  // currently 2 chars less editable
     custom_element.description,
-    NULL, "Element name"
+    NULL, NULL, NULL,                          "Enter element name"
   }
 };
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int xsize, ysize;
   char *value;
-  char *text_above, *infotext;
+  char *text_above, *text_above_cropped, *infotext;
 } textarea_info[ED_NUM_TEXTAREAS] =
 {
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    ED_TEXTAREA_ID_ENVELOPE_INFO,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
     GADGET_ID_ENVELOPE_INFO,
     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
     NULL,
-    "Envelope Content:", "Envelope Content"
+    "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
   }
 };
 
 static struct ValueTextInfo options_time_or_steps[] =
 {
-  { 0,                         "seconds"                       },
-  { 1,                         "steps"                         },
+  { 0,                                 "seconds"                       },
+  { 1,                                 "steps"                         },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_time_score_base[] =
 {
-  { 1,                         "per second/step"               },
-  { 10,                                "per 10 seconds/steps"          },
+  { 1,                                 "per second/step"               },
+  { 10,                                        "per 10 seconds/steps"          },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_game_engine_type[] =
 {
-  { GAME_ENGINE_TYPE_RND,      "Rocks'n'Diamonds"              },
-  { GAME_ENGINE_TYPE_EM,       "Emerald Mine"                  },
-  { GAME_ENGINE_TYPE_SP,       "Supaplex"                      },
-  { GAME_ENGINE_TYPE_MM,       "Mirror Magic"                  },
+  { GAME_ENGINE_TYPE_RND,              "Rocks'n'Diamonds"              },
+  { GAME_ENGINE_TYPE_BD,               "Boulder Dash"                  },
+  { GAME_ENGINE_TYPE_EM,               "Emerald Mine"                  },
+  { GAME_ENGINE_TYPE_SP,               "Supaplex"                      },
+  { GAME_ENGINE_TYPE_MM,               "Mirror Magic"                  },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_levelset_save_mode[] =
 {
-  { LEVELSET_SAVE_MODE_UPDATE, "Update this level set"         },
-  { LEVELSET_SAVE_MODE_CREATE, "Create new level set"          },
+  { LEVELSET_SAVE_MODE_UPDATE,         "Update this level set"         },
+  { LEVELSET_SAVE_MODE_CREATE,         "Create new level set"          },
+
+  { -1,                                        NULL                            }
+};
+
+static struct ValueTextInfo options_bd_gravity_direction[] =
+{
+  { GD_MV_DOWN,                                "down"                          },
+  { GD_MV_UP,                          "up"                            },
+  { GD_MV_LEFT,                                "left"                          },
+  { GD_MV_RIGHT,                       "right"                         },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_wind_direction[] =
 {
-  { MV_START_NONE,             "none"                          },
-  { MV_START_LEFT,             "left"                          },
-  { MV_START_RIGHT,            "right"                         },
-  { MV_START_UP,               "up"                            },
-  { MV_START_DOWN,             "down"                          },
+  { MV_START_NONE,                     "none"                          },
+  { MV_START_LEFT,                     "left"                          },
+  { MV_START_RIGHT,                    "right"                         },
+  { MV_START_UP,                       "up"                            },
+  { MV_START_DOWN,                     "down"                          },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_player_speed[] =
 {
-  { 0,                         "frozen"                        },
-  { 1,                         "very slow"                     },
-  { 2,                         "slow"                          },
-  { 4,                         "normal"                        },
-  { 8,                         "fast"                          },
-  { 16,                                "very fast"                     },
-  { 32,                                "ultrafast"                     },
+  { 0,                                 "frozen"                        },
+  { 1,                                 "very slow"                     },
+  { 2,                                 "slow"                          },
+  { 4,                                 "normal"                        },
+  { 8,                                 "fast"                          },
+  { 16,                                        "very fast"                     },
+  { 32,                                        "ultrafast"                     },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_access_type[] =
 {
-  { EP_WALKABLE,               "walkable"                      },
-  { EP_PASSABLE,               "passable"                      },
+  { EP_WALKABLE,                       "walkable"                      },
+  { EP_PASSABLE,                       "passable"                      },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_access_layer[] =
 {
-  { EP_ACCESSIBLE_OVER,                "over"                          },
-  { EP_ACCESSIBLE_INSIDE,      "inside"                        },
-  { EP_ACCESSIBLE_UNDER,       "under"                         },
+  { EP_ACCESSIBLE_OVER,                        "over"                          },
+  { EP_ACCESSIBLE_INSIDE,              "inside"                        },
+  { EP_ACCESSIBLE_UNDER,               "under"                         },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_access_protected[] =
 {
-  { 0,                         "unprotected"                   },
-  { 1,                         "protected"                     },
+  { 0,                                 "unprotected"                   },
+  { 1,                                 "protected"                     },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_access_direction[] =
 {
-  { MV_NO_DIRECTION,           "no direction"                  },
-  { MV_LEFT,                   "left"                          },
-  { MV_RIGHT,                  "right"                         },
-  { MV_UP,                     "up"                            },
-  { MV_DOWN,                   "down"                          },
-  { MV_LEFT  | MV_UP,          "left + up"                     },
-  { MV_LEFT  | MV_DOWN,                "left + down"                   },
-  { MV_RIGHT | MV_UP,          "right + up"                    },
-  { MV_RIGHT | MV_DOWN,                "right + down"                  },
-  { MV_HORIZONTAL,             "horizontal"                    },
-  { MV_VERTICAL,               "vertical"                      },
-  { MV_HORIZONTAL | MV_UP,     "horizontal + up"               },
-  { MV_HORIZONTAL | MV_DOWN,   "horizontal + down"             },
-  { MV_VERTICAL   | MV_LEFT,   "vertical + left"               },
-  { MV_VERTICAL   | MV_RIGHT,  "vertical + right"              },
-  { MV_ALL_DIRECTIONS,         "all directions"                },
-
-  { -1,                                NULL                            }
+  { MV_NO_DIRECTION,                   "no direction"                  },
+  { MV_LEFT,                           "left"                          },
+  { MV_RIGHT,                          "right"                         },
+  { MV_UP,                             "up"                            },
+  { MV_DOWN,                           "down"                          },
+  { MV_LEFT  | MV_UP,                  "left + up"                     },
+  { MV_LEFT  | MV_DOWN,                        "left + down"                   },
+  { MV_RIGHT | MV_UP,                  "right + up"                    },
+  { MV_RIGHT | MV_DOWN,                        "right + down"                  },
+  { MV_HORIZONTAL,                     "horizontal"                    },
+  { MV_VERTICAL,                       "vertical"                      },
+  { MV_HORIZONTAL | MV_UP,             "horizontal + up"               },
+  { MV_HORIZONTAL | MV_DOWN,           "horizontal + down"             },
+  { MV_VERTICAL   | MV_LEFT,           "vertical + left"               },
+  { MV_VERTICAL   | MV_RIGHT,          "vertical + right"              },
+  { MV_ALL_DIRECTIONS,                 "all directions"                },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_walk_to_action[] =
 {
-  { EP_DIGGABLE,               "diggable"                      },
-  { EP_COLLECTIBLE_ONLY,       "collectible"                   },
-  { EP_DROPPABLE,              "collectible & droppable"       },
-  { EP_THROWABLE,              "collectible & throwable"       },
-  { EP_PUSHABLE,               "pushable"                      },
+  { EP_DIGGABLE,                       "diggable"                      },
+  { EP_COLLECTIBLE_ONLY,               "collectible"                   },
+  { EP_DROPPABLE,                      "collectible & droppable"       },
+  { EP_THROWABLE,                      "collectible & throwable"       },
+  { EP_PUSHABLE,                       "pushable"                      },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_move_pattern[] =
 {
-  { MV_LEFT,                   "left"                          },
-  { MV_RIGHT,                  "right"                         },
-  { MV_UP,                     "up"                            },
-  { MV_DOWN,                   "down"                          },
-  { MV_HORIZONTAL,             "horizontal"                    },
-  { MV_VERTICAL,               "vertical"                      },
-  { MV_ALL_DIRECTIONS,         "all directions"                },
-  { MV_WIND_DIRECTION,         "wind direction"                },
-  { MV_TOWARDS_PLAYER,         "towards player"                },
-  { MV_AWAY_FROM_PLAYER,       "away from player"              },
-  { MV_ALONG_LEFT_SIDE,                "along left side"               },
-  { MV_ALONG_RIGHT_SIDE,       "along right side"              },
-  { MV_TURNING_LEFT,           "turning left"                  },
-  { MV_TURNING_RIGHT,          "turning right"                 },
-  { MV_TURNING_LEFT_RIGHT,     "turning left, right"           },
-  { MV_TURNING_RIGHT_LEFT,     "turning right, left"           },
-  { MV_TURNING_RANDOM,         "turning random"                },
-  { MV_MAZE_RUNNER,            "maze runner style"             },
-  { MV_MAZE_HUNTER,            "maze hunter style"             },
-  { MV_WHEN_PUSHED,            "when pushed"                   },
-  { MV_WHEN_DROPPED,           "when dropped/thrown"           },
-
-  { -1,                                NULL                            }
+  { MV_LEFT,                           "left"                          },
+  { MV_RIGHT,                          "right"                         },
+  { MV_UP,                             "up"                            },
+  { MV_DOWN,                           "down"                          },
+  { MV_HORIZONTAL,                     "horizontal"                    },
+  { MV_VERTICAL,                       "vertical"                      },
+  { MV_ALL_DIRECTIONS,                 "all directions"                },
+  { MV_WIND_DIRECTION,                 "wind direction"                },
+  { MV_TOWARDS_PLAYER,                 "towards player"                },
+  { MV_AWAY_FROM_PLAYER,               "away from player"              },
+  { MV_ALONG_LEFT_SIDE,                        "along left side"               },
+  { MV_ALONG_RIGHT_SIDE,               "along right side"              },
+  { MV_TURNING_LEFT,                   "turning left"                  },
+  { MV_TURNING_RIGHT,                  "turning right"                 },
+  { MV_TURNING_LEFT_RIGHT,             "turning left, right"           },
+  { MV_TURNING_RIGHT_LEFT,             "turning right, left"           },
+  { MV_TURNING_RANDOM,                 "turning random"                },
+  { MV_MAZE_RUNNER,                    "maze runner style"             },
+  { MV_MAZE_HUNTER,                    "maze hunter style"             },
+  { MV_WHEN_PUSHED,                    "when pushed"                   },
+  { MV_WHEN_DROPPED,                   "when dropped/thrown"           },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_move_direction[] =
 {
-  { MV_START_AUTOMATIC,                "automatic"                     },
-  { MV_START_LEFT,             "left"                          },
-  { MV_START_RIGHT,            "right"                         },
-  { MV_START_UP,               "up"                            },
-  { MV_START_DOWN,             "down"                          },
-  { MV_START_RANDOM,           "random"                        },
-  { MV_START_PREVIOUS,         "previous"                      },
+  { MV_START_AUTOMATIC,                        "automatic"                     },
+  { MV_START_LEFT,                     "left"                          },
+  { MV_START_RIGHT,                    "right"                         },
+  { MV_START_UP,                       "up"                            },
+  { MV_START_DOWN,                     "down"                          },
+  { MV_START_RANDOM,                   "random"                        },
+  { MV_START_PREVIOUS,                 "previous"                      },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_move_stepsize[] =
 {
-  { 0,                         "not moving"                    },
-  { 1,                         "very slow"                     },
-  { 2,                         "slow"                          },
-  { 4,                         "normal"                        },
-  { 8,                         "fast"                          },
-  { 16,                                "very fast"                     },
-  { 32,                                "even faster"                   },
+  { 0,                                 "not moving"                    },
+  { 1,                                 "very slow"                     },
+  { 2,                                 "slow"                          },
+  { 4,                                 "normal"                        },
+  { 8,                                 "fast"                          },
+  { 16,                                        "very fast"                     },
+  { 32,                                        "even faster"                   },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_move_leave_type[] =
 {
-  { LEAVE_TYPE_UNLIMITED,      "leave behind"                  },
-  { LEAVE_TYPE_LIMITED,                "change it to"                  },
+  { LEAVE_TYPE_UNLIMITED,              "leave behind"                  },
+  { LEAVE_TYPE_LIMITED,                        "change it to"                  },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_smash_targets[] =
 {
-  { EP_CAN_SMASH_PLAYER,       "player"                        },
+  { EP_CAN_SMASH_PLAYER,               "player"                        },
 #if 0
-  { EP_CAN_SMASH_ENEMIES,      "enemies"                       },
+  { EP_CAN_SMASH_ENEMIES,              "enemies"                       },
 #endif
-  { EP_CAN_SMASH_EVERYTHING,   "everything"                    },
+  { EP_CAN_SMASH_EVERYTHING,           "everything"                    },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_slippery_type[] =
 {
-  { SLIPPERY_ANY_RANDOM,       "random"                        },
-  { SLIPPERY_ANY_LEFT_RIGHT,   "left, right"                   },
-  { SLIPPERY_ANY_RIGHT_LEFT,   "right, left"                   },
-  { SLIPPERY_ONLY_LEFT,                "only left"                     },
-  { SLIPPERY_ONLY_RIGHT,       "only right"                    },
+  { SLIPPERY_ANY_RANDOM,               "random"                        },
+  { SLIPPERY_ANY_LEFT_RIGHT,           "left, right"                   },
+  { SLIPPERY_ANY_RIGHT_LEFT,           "right, left"                   },
+  { SLIPPERY_ONLY_LEFT,                        "only left"                     },
+  { SLIPPERY_ONLY_RIGHT,               "only right"                    },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_deadliness[] =
 {
-  { EP_DONT_RUN_INTO,          "running into"                  },
-  { EP_DONT_COLLIDE_WITH,      "colliding with"                },
-  { EP_DONT_GET_HIT_BY,                "getting hit by"                },
-  { EP_DONT_TOUCH,             "touching"                      },
+  { EP_DONT_RUN_INTO,                  "running into"                  },
+  { EP_DONT_COLLIDE_WITH,              "colliding with"                },
+  { EP_DONT_GET_HIT_BY,                        "getting hit by"                },
+  { EP_DONT_TOUCH,                     "touching"                      },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_explosion_type[] =
 {
-  { EXPLODES_3X3,              "3x3"                           },
-  { EXPLODES_CROSS,            "3+3"                           },
-  { EXPLODES_1X1,              "1x1"                           },
+  { EXPLODES_3X3,                      "3x3"                           },
+  { EXPLODES_CROSS,                    "3+3"                           },
+  { EXPLODES_1X1,                      "1x1"                           },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_time_units[] =
 {
-  { 1,                         "frames"                        },
-  { FRAMES_PER_SECOND,         "seconds"                       },
+  { 1,                                 "frames"                        },
+  { FRAMES_PER_SECOND,                 "seconds"                       },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_direct_action[] =
 {
-  { CE_TOUCHED_BY_PLAYER,      "touched by player"             },
-  { CE_PRESSED_BY_PLAYER,      "pressed by player"             },
-  { CE_SWITCHED_BY_PLAYER,     "switched by player"            },
-  { CE_SNAPPED_BY_PLAYER,      "snapped by player"             },
-  { CE_PUSHED_BY_PLAYER,       "pushed by player"              },
-  { CE_ENTERED_BY_PLAYER,      "entered by player"             },
-  { CE_LEFT_BY_PLAYER,         "left by player"                },
-  { CE_DROPPED_BY_PLAYER,      "dropped/thrown by player"      },
-  { CE_SWITCHED,               "switched"                      },
-  { CE_HITTING_SOMETHING,      "hitting something"             },
-  { CE_HIT_BY_SOMETHING,       "hit by something"              },
+  { CE_TOUCHED_BY_PLAYER,              "touched by player"             },
+  { CE_PRESSED_BY_PLAYER,              "pressed by player"             },
+  { CE_SWITCHED_BY_PLAYER,             "switched by player"            },
+  { CE_SNAPPED_BY_PLAYER,              "snapped by player"             },
+  { CE_PUSHED_BY_PLAYER,               "pushed by player"              },
+  { CE_ENTERED_BY_PLAYER,              "entered by player"             },
+  { CE_LEFT_BY_PLAYER,                 "left by player"                },
+  { CE_DROPPED_BY_PLAYER,              "dropped/thrown by player"      },
+  { CE_SWITCHED,                       "switched"                      },
+  { CE_HITTING_SOMETHING,              "hitting something"             },
+  { CE_HIT_BY_SOMETHING,               "hit by something"              },
 #if 0
-  { CE_BLOCKED,                        "blocked"                       },
+  { CE_BLOCKED,                                "blocked"                       },
 #endif
-  { CE_IMPACT,                 "impact (on something)"         },
-  { CE_SMASHED,                        "smashed (from above)"          },
+  { CE_IMPACT,                         "impact (on something)"         },
+  { CE_SMASHED,                                "smashed (from above)"          },
 #if 0
-  { CE_VALUE_CHANGES,          "CE value changes"              },
-  { CE_SCORE_CHANGES,          "CE score changes"              },
+  { CE_VALUE_CHANGES,                  "CE value changes"              },
+  { CE_SCORE_CHANGES,                  "CE score changes"              },
 #endif
-  { CE_VALUE_GETS_ZERO,                "CE value gets 0"               },
-  { CE_SCORE_GETS_ZERO,                "CE score gets 0"               },
-  { CE_UNDEFINED,              " "                             },
-  { CE_HEADLINE_SPECIAL_EVENTS,        "[mouse events]"                },
-  { CE_CLICKED_BY_MOUSE,       "clicked by mouse"              },
-  { CE_PRESSED_BY_MOUSE,       "pressed by mouse"              },
-
-  { -1,                                NULL                            }
+  { CE_VALUE_GETS_ZERO,                        "CE value gets 0"               },
+  { CE_SCORE_GETS_ZERO,                        "CE score gets 0"               },
+  { CE_UNDEFINED,                      " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,                "[mouse events]"                },
+  { CE_CLICKED_BY_MOUSE,               "clicked by mouse"              },
+  { CE_PRESSED_BY_MOUSE,               "pressed by mouse"              },
+  { CE_UNDEFINED,                      " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,                "[static states]"               },
+  { CE_NEXT_TO_PLAYER,                 "next to player"                },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_other_action[] =
 {
-  { CE_PLAYER_TOUCHES_X,       "player touches"                },
-  { CE_PLAYER_PRESSES_X,       "player presses"                },
-  { CE_PLAYER_SWITCHES_X,      "player switches"               },
-  { CE_PLAYER_SNAPS_X,         "player snaps"                  },
-  { CE_PLAYER_PUSHES_X,                "player pushes"                 },
-  { CE_PLAYER_ENTERS_X,                "player enters"                 },
-  { CE_PLAYER_LEAVES_X,                "player leaves"                 },
-  { CE_PLAYER_DIGS_X,          "player digs"                   },
-  { CE_PLAYER_COLLECTS_X,      "player collects"               },
-  { CE_PLAYER_DROPS_X,         "player drops/throws"           },
-  { CE_TOUCHING_X,             "touching"                      },
-  { CE_HITTING_X,              "hitting"                       },
-  { CE_DIGGING_X,              "digging"                       },
-  { CE_HIT_BY_X,               "hit by"                        },
-  { CE_SWITCH_OF_X,            "switch of"                     },
-  { CE_CHANGE_OF_X,            "change by page of"             },
-  { CE_EXPLOSION_OF_X,         "explosion of"                  },
-  { CE_MOVE_OF_X,              "move of"                       },
-  { CE_CREATION_OF_X,          "creation of"                   },
-  { CE_VALUE_CHANGES_OF_X,     "CE value changes of"           },
-  { CE_SCORE_CHANGES_OF_X,     "CE score changes of"           },
-  { CE_VALUE_GETS_ZERO_OF_X,   "CE value gets 0 of"            },
-  { CE_SCORE_GETS_ZERO_OF_X,   "CE score gets 0 of"            },
-  { CE_UNDEFINED,              " "                             },
-  { CE_HEADLINE_SPECIAL_EVENTS,        "[mouse events]"                },
-  { CE_MOUSE_CLICKED_ON_X,     "mouse clicked on"              },
-  { CE_MOUSE_PRESSED_ON_X,     "mouse pressed on"              },
-
-  { -1,                                NULL                            }
+  { CE_PLAYER_TOUCHES_X,               "player touches"                },
+  { CE_PLAYER_PRESSES_X,               "player presses"                },
+  { CE_PLAYER_SWITCHES_X,              "player switches"               },
+  { CE_PLAYER_SNAPS_X,                 "player snaps"                  },
+  { CE_PLAYER_PUSHES_X,                        "player pushes"                 },
+  { CE_PLAYER_ENTERS_X,                        "player enters"                 },
+  { CE_PLAYER_LEAVES_X,                        "player leaves"                 },
+  { CE_PLAYER_DIGS_X,                  "player digs"                   },
+  { CE_PLAYER_COLLECTS_X,              "player collects"               },
+  { CE_PLAYER_DROPS_X,                 "player drops/throws"           },
+  { CE_TOUCHING_X,                     "touching"                      },
+  { CE_HITTING_X,                      "hitting"                       },
+  { CE_DIGGING_X,                      "digging"                       },
+  { CE_HIT_BY_X,                       "hit by"                        },
+  { CE_SWITCH_OF_X,                    "switch of"                     },
+  { CE_CHANGE_OF_X,                    "change by page of"             },
+  { CE_EXPLOSION_OF_X,                 "explosion of"                  },
+  { CE_MOVE_OF_X,                      "move of"                       },
+  { CE_CREATION_OF_X,                  "creation of"                   },
+  { CE_VALUE_CHANGES_OF_X,             "CE value changes of"           },
+  { CE_SCORE_CHANGES_OF_X,             "CE score changes of"           },
+  { CE_VALUE_GETS_ZERO_OF_X,           "CE value gets 0 of"            },
+  { CE_SCORE_GETS_ZERO_OF_X,           "CE score gets 0 of"            },
+  { CE_UNDEFINED,                      " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,                "[mouse events]"                },
+  { CE_MOUSE_CLICKED_ON_X,             "mouse clicked on"              },
+  { CE_MOUSE_PRESSED_ON_X,             "mouse pressed on"              },
+  { CE_UNDEFINED,                      " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,                "[static states]"               },
+  { CE_PLAYER_NEXT_TO_X,               "player next to"                },
+  { CE_NEXT_TO_X,                      "next to"                       },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_trigger_side[] =
 {
-  { CH_SIDE_LEFT,              "left"                          },
-  { CH_SIDE_RIGHT,             "right"                         },
-  { CH_SIDE_TOP,               "top"                           },
-  { CH_SIDE_BOTTOM,            "bottom"                        },
-  { CH_SIDE_LEFT_RIGHT,                "left/right"                    },
-  { CH_SIDE_TOP_BOTTOM,                "top/bottom"                    },
-  { CH_SIDE_ANY,               "any"                           },
+  { CH_SIDE_LEFT,                      "left"                          },
+  { CH_SIDE_RIGHT,                     "right"                         },
+  { CH_SIDE_TOP,                       "top"                           },
+  { CH_SIDE_BOTTOM,                    "bottom"                        },
+  { CH_SIDE_LEFT_RIGHT,                        "left/right"                    },
+  { CH_SIDE_TOP_BOTTOM,                        "top/bottom"                    },
+  { CH_SIDE_ANY,                       "any"                           },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_trigger_player[] =
 {
-  { CH_PLAYER_1,               "1"                             },
-  { CH_PLAYER_2,               "2"                             },
-  { CH_PLAYER_3,               "3"                             },
-  { CH_PLAYER_4,               "4"                             },
-  { CH_PLAYER_ANY,             "any"                           },
+  { CH_PLAYER_1,                       "1"                             },
+  { CH_PLAYER_2,                       "2"                             },
+  { CH_PLAYER_3,                       "3"                             },
+  { CH_PLAYER_4,                       "4"                             },
+  { CH_PLAYER_ANY,                     "any"                           },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_trigger_page[] =
 {
-  { (1 << 0),                  "1"                             },
-  { (1 << 1),                  "2"                             },
-  { (1 << 2),                  "3"                             },
-  { (1 << 3),                  "4"                             },
-  { (1 << 4),                  "5"                             },
-  { (1 << 5),                  "6"                             },
-  { (1 << 6),                  "7"                             },
-  { (1 << 7),                  "8"                             },
-  { (1 << 8),                  "9"                             },
-  { (1 << 9),                  "10"                            },
-  { (1 << 10),                 "11"                            },
-  { (1 << 11),                 "12"                            },
-  { (1 << 12),                 "13"                            },
-  { (1 << 13),                 "14"                            },
-  { (1 << 14),                 "15"                            },
-  { (1 << 15),                 "16"                            },
-  { (1 << 16),                 "17"                            },
-  { (1 << 17),                 "18"                            },
-  { (1 << 18),                 "19"                            },
-  { (1 << 19),                 "20"                            },
-  { (1 << 20),                 "21"                            },
-  { (1 << 21),                 "22"                            },
-  { (1 << 22),                 "23"                            },
-  { (1 << 23),                 "24"                            },
-  { (1 << 24),                 "25"                            },
-  { (1 << 25),                 "26"                            },
-  { (1 << 26),                 "27"                            },
-  { (1 << 27),                 "28"                            },
-  { (1 << 28),                 "29"                            },
-  { (1 << 29),                 "30"                            },
-  { (1 << 30),                 "31"                            },
-  { (1 << 31),                 "32"                            },
-  { CH_PAGE_ANY,               "any"                           },
-
-  { -1,                                NULL                            }
+  { (1u << 0),                         "1"                             },
+  { (1u << 1),                         "2"                             },
+  { (1u << 2),                         "3"                             },
+  { (1u << 3),                         "4"                             },
+  { (1u << 4),                         "5"                             },
+  { (1u << 5),                         "6"                             },
+  { (1u << 6),                         "7"                             },
+  { (1u << 7),                         "8"                             },
+  { (1u << 8),                         "9"                             },
+  { (1u << 9),                         "10"                            },
+  { (1u << 10),                                "11"                            },
+  { (1u << 11),                                "12"                            },
+  { (1u << 12),                                "13"                            },
+  { (1u << 13),                                "14"                            },
+  { (1u << 14),                                "15"                            },
+  { (1u << 15),                                "16"                            },
+  { (1u << 16),                                "17"                            },
+  { (1u << 17),                                "18"                            },
+  { (1u << 18),                                "19"                            },
+  { (1u << 19),                                "20"                            },
+  { (1u << 20),                                "21"                            },
+  { (1u << 21),                                "22"                            },
+  { (1u << 22),                                "23"                            },
+  { (1u << 23),                                "24"                            },
+  { (1u << 24),                                "25"                            },
+  { (1u << 25),                                "26"                            },
+  { (1u << 26),                                "27"                            },
+  { (1u << 27),                                "28"                            },
+  { (1u << 28),                                "29"                            },
+  { (1u << 29),                                "30"                            },
+  { (1u << 30),                                "31"                            },
+  { (1u << 31),                                "32"                            },
+  { CH_PAGE_ANY,                       "any"                           },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_change_replace_when[] =
 {
-  { CP_WHEN_EMPTY,             "empty"                         },
-  { CP_WHEN_WALKABLE,          "walkable"                      },
-  { CP_WHEN_DIGGABLE,          "diggable"                      },
-  { CP_WHEN_COLLECTIBLE,       "collectible"                   },
-  { CP_WHEN_REMOVABLE,         "removable"                     },
-  { CP_WHEN_DESTRUCTIBLE,      "destructible"                  },
+  { CP_WHEN_EMPTY,                     "empty"                         },
+  { CP_WHEN_WALKABLE,                  "walkable"                      },
+  { CP_WHEN_DIGGABLE,                  "diggable"                      },
+  { CP_WHEN_COLLECTIBLE,               "collectible"                   },
+  { CP_WHEN_REMOVABLE,                 "removable"                     },
+  { CP_WHEN_DESTRUCTIBLE,              "destructible"                  },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_type[] =
 {
-  { CA_NO_ACTION,              "no action"                     },
-  { CA_UNDEFINED,              " "                             },
-  { CA_HEADLINE_LEVEL_ACTIONS, "[level]"                       },
-  { CA_RESTART_LEVEL,          "restart level"                 },
-  { CA_SHOW_ENVELOPE,          "show envelope"                 },
-  { CA_SET_LEVEL_TIME,         "set time"                      },
-  { CA_SET_LEVEL_SCORE,                "set score"                     },
-  { CA_SET_LEVEL_GEMS,         "set gems"                      },
-  { CA_SET_LEVEL_WIND,         "set wind dir."                 },
-  { CA_SET_LEVEL_RANDOM_SEED,  "set random seed"               },
-  { CA_UNDEFINED,              " "                             },
-  { CA_HEADLINE_PLAYER_ACTIONS,        "[player]"                      },
-  { CA_MOVE_PLAYER,            "move player"                   },
-  { CA_MOVE_PLAYER_NEW,                "move player new"               },
-  { CA_EXIT_PLAYER,            "exit player"                   },
-  { CA_KILL_PLAYER,            "kill player"                   },
-  { CA_SET_PLAYER_KEYS,                "set keys"                      },
-  { CA_SET_PLAYER_SPEED,       "set speed"                     },
-  { CA_SET_PLAYER_SHIELD,      "set shield"                    },
-  { CA_SET_PLAYER_GRAVITY,     "set gravity"                   },
-  { CA_SET_PLAYER_ARTWORK,     "set artwork"                   },
-  { CA_SET_PLAYER_INVENTORY,   "set inventory"                 },
-  { CA_UNDEFINED,              " "                             },
-  { CA_HEADLINE_CE_ACTIONS,    "[CE]"                          },
-  { CA_SET_CE_VALUE,           "set CE value"                  },
-  { CA_SET_CE_SCORE,           "set CE score"                  },
-  { CA_SET_CE_ARTWORK,         "set CE artwork"                },
-  { CA_UNDEFINED,              " "                             },
-  { CA_HEADLINE_ENGINE_ACTIONS,        "[engine]"                      },
-  { CA_SET_ENGINE_SCAN_MODE,   "set scan mode"                 },
-
-  { -1,                                NULL                            }
+  { CA_NO_ACTION,                      "no action"                     },
+  { CA_UNDEFINED,                      " "                             },
+  { CA_HEADLINE_LEVEL_ACTIONS,         "[level]"                       },
+  { CA_RESTART_LEVEL,                  "restart level"                 },
+  { CA_SHOW_ENVELOPE,                  "show envelope"                 },
+  { CA_SET_LEVEL_TIME,                 "set time"                      },
+  { CA_SET_LEVEL_SCORE,                        "set score"                     },
+  { CA_SET_LEVEL_GEMS,                 "set gems"                      },
+  { CA_SET_LEVEL_WIND,                 "set wind dir."                 },
+  { CA_SET_LEVEL_RANDOM_SEED,          "set random seed"               },
+  { CA_UNDEFINED,                      " "                             },
+  { CA_HEADLINE_PLAYER_ACTIONS,                "[player]"                      },
+  { CA_MOVE_PLAYER,                    "move player"                   },
+  { CA_MOVE_PLAYER_NEW,                        "move player new"               },
+  { CA_EXIT_PLAYER,                    "exit player"                   },
+  { CA_KILL_PLAYER,                    "kill player"                   },
+  { CA_SET_PLAYER_KEYS,                        "set keys"                      },
+  { CA_SET_PLAYER_SPEED,               "set speed"                     },
+  { CA_SET_PLAYER_SHIELD,              "set shield"                    },
+  { CA_SET_PLAYER_GRAVITY,             "set gravity"                   },
+  { CA_SET_PLAYER_ARTWORK,             "set artwork"                   },
+  { CA_SET_PLAYER_INVENTORY,           "set inventory"                 },
+  { CA_UNDEFINED,                      " "                             },
+  { CA_HEADLINE_CE_ACTIONS,            "[CE]"                          },
+  { CA_SET_CE_VALUE,                   "set CE value"                  },
+  { CA_SET_CE_SCORE,                   "set CE score"                  },
+  { CA_SET_CE_ARTWORK,                 "set CE artwork"                },
+  { CA_UNDEFINED,                      " "                             },
+  { CA_HEADLINE_ENGINE_ACTIONS,                "[engine]"                      },
+  { CA_SET_ENGINE_SCAN_MODE,           "set scan mode"                 },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_mode_none[] =
 {
-  { CA_MODE_UNDEFINED,         " "                             },
+  { CA_MODE_UNDEFINED,                 " "                             },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_mode_assign[] =
 {
-  { CA_MODE_SET,               "="                             },
+  { CA_MODE_SET,                       "="                             },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_mode_add_remove[] =
 {
-  { CA_MODE_ADD,               "+"                             },
-  { CA_MODE_SUBTRACT,          "-"                             },
+  { CA_MODE_ADD,                       "+"                             },
+  { CA_MODE_SUBTRACT,                  "-"                             },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_mode_calculate[] =
 {
-  { CA_MODE_SET,               "="                             },
-  { CA_MODE_ADD,               "+"                             },
-  { CA_MODE_SUBTRACT,          "-"                             },
-  { CA_MODE_MULTIPLY,          "*"                             },
-  { CA_MODE_DIVIDE,            "/"                             },
-  { CA_MODE_MODULO,            "%"                             },
+  { CA_MODE_SET,                       "="                             },
+  { CA_MODE_ADD,                       "+"                             },
+  { CA_MODE_SUBTRACT,                  "-"                             },
+  { CA_MODE_MULTIPLY,                  "*"                             },
+  { CA_MODE_DIVIDE,                    "/"                             },
+  { CA_MODE_MODULO,                    "%"                             },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_none[] =
 {
-  { CA_ARG_UNDEFINED,          "         "                     },
+  { CA_ARG_UNDEFINED,                  "         "                     },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_player[] =
 {
-  { CA_ARG_PLAYER_HEADLINE,    "[player]"                      },
-  { CA_ARG_PLAYER_1,           "1"                             },
-  { CA_ARG_PLAYER_2,           "2"                             },
-  { CA_ARG_PLAYER_3,           "3"                             },
-  { CA_ARG_PLAYER_4,           "4"                             },
-  { CA_ARG_PLAYER_ANY,         "any"                           },
-  { CA_ARG_PLAYER_TRIGGER,     "trigger"                       },
-  { CA_ARG_PLAYER_ACTION,      "action ->"                     },
+  { CA_ARG_PLAYER_HEADLINE,            "[player]"                      },
+  { CA_ARG_PLAYER_1,                   "1"                             },
+  { CA_ARG_PLAYER_2,                   "2"                             },
+  { CA_ARG_PLAYER_3,                   "3"                             },
+  { CA_ARG_PLAYER_4,                   "4"                             },
+  { CA_ARG_PLAYER_ANY,                 "any"                           },
+  { CA_ARG_PLAYER_TRIGGER,             "trigger"                       },
+  { CA_ARG_PLAYER_ACTION,              "action ->"                     },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_number[] =
 {
-  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
-  { CA_ARG_0,                  "0"                             },
-  { CA_ARG_1,                  "1"                             },
-  { CA_ARG_2,                  "2"                             },
-  { CA_ARG_3,                  "3"                             },
-  { CA_ARG_4,                  "4"                             },
-  { CA_ARG_5,                  "5"                             },
-  { CA_ARG_10,                 "10"                            },
-  { CA_ARG_100,                        "100"                           },
-  { CA_ARG_1000,               "1000"                          },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_MIN,         "min"                           },
-  { CA_ARG_NUMBER_MAX,         "max"                           },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_RESET,       "reset"                         },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_CE_VALUE,    "CE value"                      },
-  { CA_ARG_NUMBER_CE_SCORE,    "CE score"                      },
-  { CA_ARG_NUMBER_CE_DELAY,    "CE delay"                      },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_LEVEL_TIME,  "time"                          },
-  { CA_ARG_NUMBER_LEVEL_GEMS,  "gems"                          },
-  { CA_ARG_NUMBER_LEVEL_SCORE, "score"                         },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_CV_HEADLINE,        "[CE value]"                    },
-  { CA_ARG_ELEMENT_CV_TARGET,  "target"                        },
-  { CA_ARG_ELEMENT_CV_TRIGGER, "trigger"                       },
-  { CA_ARG_ELEMENT_CV_ACTION,  "action ->"                     },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_CS_HEADLINE,        "[CE score]"                    },
-  { CA_ARG_ELEMENT_CS_TARGET,  "target"                        },
-  { CA_ARG_ELEMENT_CS_TRIGGER, "trigger"                       },
-  { CA_ARG_ELEMENT_CS_ACTION,  "action ->"                     },
-
-  { -1,                                NULL                            }
+  { CA_ARG_NUMBER_HEADLINE,            "[number]"                      },
+  { CA_ARG_0,                          "0"                             },
+  { CA_ARG_1,                          "1"                             },
+  { CA_ARG_2,                          "2"                             },
+  { CA_ARG_3,                          "3"                             },
+  { CA_ARG_4,                          "4"                             },
+  { CA_ARG_5,                          "5"                             },
+  { CA_ARG_10,                         "10"                            },
+  { CA_ARG_100,                                "100"                           },
+  { CA_ARG_1000,                       "1000"                          },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_MIN,                 "min"                           },
+  { CA_ARG_NUMBER_MAX,                 "max"                           },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_RESET,               "reset"                         },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_CE_VALUE,            "CE value"                      },
+  { CA_ARG_NUMBER_CE_SCORE,            "CE score"                      },
+  { CA_ARG_NUMBER_CE_DELAY,            "CE delay"                      },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_LEVEL_TIME,          "time"                          },
+  { CA_ARG_NUMBER_LEVEL_GEMS,          "gems"                          },
+  { CA_ARG_NUMBER_LEVEL_SCORE,         "score"                         },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_CV_HEADLINE,                "[CE value]"                    },
+  { CA_ARG_ELEMENT_CV_TARGET,          "target"                        },
+  { CA_ARG_ELEMENT_CV_TRIGGER,         "trigger"                       },
+  { CA_ARG_ELEMENT_CV_ACTION,          "action ->"                     },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_CS_HEADLINE,                "[CE score]"                    },
+  { CA_ARG_ELEMENT_CS_TARGET,          "target"                        },
+  { CA_ARG_ELEMENT_CS_TRIGGER,         "trigger"                       },
+  { CA_ARG_ELEMENT_CS_ACTION,          "action ->"                     },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_value[] =
 {
-  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
-  { CA_ARG_0,                  "0"                             },
-  { CA_ARG_1,                  "1"                             },
-  { CA_ARG_2,                  "2"                             },
-  { CA_ARG_3,                  "3"                             },
-  { CA_ARG_4,                  "4"                             },
-  { CA_ARG_5,                  "5"                             },
-  { CA_ARG_10,                 "10"                            },
-  { CA_ARG_100,                        "100"                           },
-  { CA_ARG_1000,               "1000"                          },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_MIN,         "min"                           },
-  { CA_ARG_NUMBER_MAX,         "max"                           },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_RESET,       "reset"                         },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_CE_VALUE,    "CE value"                      },
-  { CA_ARG_NUMBER_CE_SCORE,    "CE score"                      },
-  { CA_ARG_NUMBER_CE_DELAY,    "CE delay"                      },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_NUMBER_LEVEL_TIME,  "time"                          },
-  { CA_ARG_NUMBER_LEVEL_GEMS,  "gems"                          },
-  { CA_ARG_NUMBER_LEVEL_SCORE, "score"                         },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_CV_HEADLINE,        "[CE value]"                    },
-  { CA_ARG_ELEMENT_CV_TARGET,  "target"                        },
-  { CA_ARG_ELEMENT_CV_TRIGGER, "trigger"                       },
-  { CA_ARG_ELEMENT_CV_ACTION,  "action ->"                     },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_CS_HEADLINE,        "[CE score]"                    },
-  { CA_ARG_ELEMENT_CS_TARGET,  "target"                        },
-  { CA_ARG_ELEMENT_CS_TRIGGER, "trigger"                       },
-  { CA_ARG_ELEMENT_CS_ACTION,  "action ->"                     },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_NR_HEADLINE,        "[element]"                     },
-  { CA_ARG_ELEMENT_NR_TARGET,  "target"                        },
-  { CA_ARG_ELEMENT_NR_TRIGGER, "trigger"                       },
-  { CA_ARG_ELEMENT_NR_ACTION,  "action ->"                     },
-
-  { -1,                                NULL                            }
+  { CA_ARG_NUMBER_HEADLINE,            "[number]"                      },
+  { CA_ARG_0,                          "0"                             },
+  { CA_ARG_1,                          "1"                             },
+  { CA_ARG_2,                          "2"                             },
+  { CA_ARG_3,                          "3"                             },
+  { CA_ARG_4,                          "4"                             },
+  { CA_ARG_5,                          "5"                             },
+  { CA_ARG_10,                         "10"                            },
+  { CA_ARG_100,                                "100"                           },
+  { CA_ARG_1000,                       "1000"                          },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_MIN,                 "min"                           },
+  { CA_ARG_NUMBER_MAX,                 "max"                           },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_RESET,               "reset"                         },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_CE_VALUE,            "CE value"                      },
+  { CA_ARG_NUMBER_CE_SCORE,            "CE score"                      },
+  { CA_ARG_NUMBER_CE_DELAY,            "CE delay"                      },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_NUMBER_LEVEL_TIME,          "time"                          },
+  { CA_ARG_NUMBER_LEVEL_GEMS,          "gems"                          },
+  { CA_ARG_NUMBER_LEVEL_SCORE,         "score"                         },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_CV_HEADLINE,                "[CE value]"                    },
+  { CA_ARG_ELEMENT_CV_TARGET,          "target"                        },
+  { CA_ARG_ELEMENT_CV_TRIGGER,         "trigger"                       },
+  { CA_ARG_ELEMENT_CV_ACTION,          "action ->"                     },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_CS_HEADLINE,                "[CE score]"                    },
+  { CA_ARG_ELEMENT_CS_TARGET,          "target"                        },
+  { CA_ARG_ELEMENT_CS_TRIGGER,         "trigger"                       },
+  { CA_ARG_ELEMENT_CS_ACTION,          "action ->"                     },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_NR_HEADLINE,                "[element]"                     },
+  { CA_ARG_ELEMENT_NR_TARGET,          "target"                        },
+  { CA_ARG_ELEMENT_NR_TRIGGER,         "trigger"                       },
+  { CA_ARG_ELEMENT_NR_ACTION,          "action ->"                     },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_envelope[] =
 {
-  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
-  { CA_ARG_1,                  "1"                             },
-  { CA_ARG_2,                  "2"                             },
-  { CA_ARG_3,                  "3"                             },
-  { CA_ARG_4,                  "4"                             },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
-  { CA_ARG_ELEMENT_TARGET,     "target"                        },
-  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
-  { CA_ARG_ELEMENT_ACTION,     "action ->"                     },
-
-  { -1,                                NULL                            }
+  { CA_ARG_NUMBER_HEADLINE,            "[number]"                      },
+  { CA_ARG_1,                          "1"                             },
+  { CA_ARG_2,                          "2"                             },
+  { CA_ARG_3,                          "3"                             },
+  { CA_ARG_4,                          "4"                             },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_HEADLINE,           "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,             "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,            "trigger"                       },
+  { CA_ARG_ELEMENT_ACTION,             "action ->"                     },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_key[] =
 {
-  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
-  { CA_ARG_1,                  "1"                             },
-  { CA_ARG_2,                  "2"                             },
-  { CA_ARG_3,                  "3"                             },
-  { CA_ARG_4,                  "4"                             },
-  { CA_ARG_5,                  "5"                             },
-  { CA_ARG_6,                  "6"                             },
-  { CA_ARG_7,                  "7"                             },
-  { CA_ARG_8,                  "8"                             },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
-  { CA_ARG_ELEMENT_TARGET,     "target"                        },
-  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
-  { CA_ARG_ELEMENT_ACTION,     "action ->"                     },
-
-  { -1,                                NULL                            }
+  { CA_ARG_NUMBER_HEADLINE,            "[number]"                      },
+  { CA_ARG_1,                          "1"                             },
+  { CA_ARG_2,                          "2"                             },
+  { CA_ARG_3,                          "3"                             },
+  { CA_ARG_4,                          "4"                             },
+  { CA_ARG_5,                          "5"                             },
+  { CA_ARG_6,                          "6"                             },
+  { CA_ARG_7,                          "7"                             },
+  { CA_ARG_8,                          "8"                             },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_HEADLINE,           "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,             "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,            "trigger"                       },
+  { CA_ARG_ELEMENT_ACTION,             "action ->"                     },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_speed[] =
 {
-  { CA_ARG_SPEED_HEADLINE,     "[speed]"                       },
-  { CA_ARG_SPEED_NOT_MOVING,   "frozen"                        },
-  { CA_ARG_SPEED_VERY_SLOW,    "very slow"                     },
-  { CA_ARG_SPEED_SLOW,         "slow"                          },
-  { CA_ARG_SPEED_NORMAL,       "normal"                        },
-  { CA_ARG_SPEED_FAST,         "fast"                          },
-  { CA_ARG_SPEED_VERY_FAST,    "very fast"                     },
-  { CA_ARG_SPEED_EVEN_FASTER,  "ultrafast"                     },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_SPEED_SLOWER,       "slower"                        },
-  { CA_ARG_SPEED_FASTER,       "faster"                        },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_SPEED_RESET,                "reset"                         },
-
-  { -1,                                NULL                            }
+  { CA_ARG_SPEED_HEADLINE,             "[speed]"                       },
+  { CA_ARG_SPEED_NOT_MOVING,           "frozen"                        },
+  { CA_ARG_SPEED_VERY_SLOW,            "very slow"                     },
+  { CA_ARG_SPEED_SLOW,                 "slow"                          },
+  { CA_ARG_SPEED_NORMAL,               "normal"                        },
+  { CA_ARG_SPEED_FAST,                 "fast"                          },
+  { CA_ARG_SPEED_VERY_FAST,            "very fast"                     },
+  { CA_ARG_SPEED_EVEN_FASTER,          "ultrafast"                     },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_SPEED_SLOWER,               "slower"                        },
+  { CA_ARG_SPEED_FASTER,               "faster"                        },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_SPEED_RESET,                        "reset"                         },
+
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_shield[] =
 {
-  { CA_ARG_SHIELD_HEADLINE,    "[shield]"                      },
-  { CA_ARG_SHIELD_OFF,         "off"                           },
-  { CA_ARG_SHIELD_NORMAL,      "normal"                        },
-  { CA_ARG_SHIELD_DEADLY,      "deadly"                        },
+  { CA_ARG_SHIELD_HEADLINE,            "[shield]"                      },
+  { CA_ARG_SHIELD_OFF,                 "off"                           },
+  { CA_ARG_SHIELD_NORMAL,              "normal"                        },
+  { CA_ARG_SHIELD_DEADLY,              "deadly"                        },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_artwork[] =
 {
-  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
-  { CA_ARG_ELEMENT_TARGET,     "target"                        },
-  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
-  { CA_ARG_ELEMENT_ACTION,     "action ->"                     },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_ELEMENT_RESET,      "reset"                         },
+  { CA_ARG_ELEMENT_HEADLINE,           "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,             "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,            "trigger"                       },
+  { CA_ARG_ELEMENT_ACTION,             "action ->"                     },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_ELEMENT_RESET,              "reset"                         },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_gravity[] =
 {
-  { CA_ARG_GRAVITY_HEADLINE,   "[gravity]"                     },
-  { CA_ARG_GRAVITY_ON,         "on"                            },
-  { CA_ARG_GRAVITY_OFF,                "off"                           },
-  { CA_ARG_GRAVITY_TOGGLE,     "toggle"                        },
+  { CA_ARG_GRAVITY_HEADLINE,           "[gravity]"                     },
+  { CA_ARG_GRAVITY_ON,                 "on"                            },
+  { CA_ARG_GRAVITY_OFF,                        "off"                           },
+  { CA_ARG_GRAVITY_TOGGLE,             "toggle"                        },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_direction[] =
 {
-  { CA_ARG_DIRECTION_HEADLINE, "[dir.]"                        },
-  { CA_ARG_DIRECTION_NONE,     "none"                          },
-  { CA_ARG_DIRECTION_LEFT,     "left"                          },
-  { CA_ARG_DIRECTION_RIGHT,    "right"                         },
-  { CA_ARG_DIRECTION_UP,       "up"                            },
-  { CA_ARG_DIRECTION_DOWN,     "down"                          },
-  { CA_ARG_DIRECTION_TRIGGER,  "trigger"                       },
-  { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                  },
+  { CA_ARG_DIRECTION_HEADLINE,         "[dir.]"                        },
+  { CA_ARG_DIRECTION_NONE,             "none"                          },
+  { CA_ARG_DIRECTION_LEFT,             "left"                          },
+  { CA_ARG_DIRECTION_RIGHT,            "right"                         },
+  { CA_ARG_DIRECTION_UP,               "up"                            },
+  { CA_ARG_DIRECTION_DOWN,             "down"                          },
+  { CA_ARG_DIRECTION_TRIGGER,          "trigger"                       },
+  { CA_ARG_DIRECTION_TRIGGER_BACK,     "-trigger"                      },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_scan_mode[] =
 {
-  { CA_ARG_SCAN_MODE_HEADLINE, "[mode]"                        },
-  { CA_ARG_SCAN_MODE_NORMAL,   "normal"                        },
-  { CA_ARG_SCAN_MODE_REVERSE,  "reverse"                       },
+  { CA_ARG_SCAN_MODE_HEADLINE,         "[mode]"                        },
+  { CA_ARG_SCAN_MODE_NORMAL,           "normal"                        },
+  { CA_ARG_SCAN_MODE_REVERSE,          "reverse"                       },
 
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_action_arg_inventory[] =
 {
-  { CA_ARG_INVENTORY_HEADLINE, "[add]"                         },
-  { CA_ARG_ELEMENT_TARGET,     "+ target"                      },
-  { CA_ARG_ELEMENT_TRIGGER,    "+ trigger"                     },
-  { CA_ARG_ELEMENT_ACTION,     "+ action"                      },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_INVENTORY_RM_HEADLINE,"[remove]"                    },
-  { CA_ARG_INVENTORY_RM_TARGET,        "- target"                      },
-  { CA_ARG_INVENTORY_RM_TRIGGER,"- trigger"                    },
-  { CA_ARG_INVENTORY_RM_ACTION,        "- action"                      },
-  { CA_ARG_INVENTORY_RM_FIRST, "- first"                       },
-  { CA_ARG_INVENTORY_RM_LAST,  "- last"                        },
-  { CA_ARG_INVENTORY_RM_ALL,   "- all"                         },
-  { CA_ARG_UNDEFINED,          " "                             },
-  { CA_ARG_INVENTORY_RESET,    "reset"                         },
-
-  { -1,                                NULL                            }
+  { CA_ARG_INVENTORY_HEADLINE,         "[add]"                         },
+  { CA_ARG_ELEMENT_TARGET,             "+ target"                      },
+  { CA_ARG_ELEMENT_TRIGGER,            "+ trigger"                     },
+  { CA_ARG_ELEMENT_ACTION,             "+ action"                      },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_INVENTORY_RM_HEADLINE,      "[remove]"                      },
+  { CA_ARG_INVENTORY_RM_TARGET,                "- target"                      },
+  { CA_ARG_INVENTORY_RM_TRIGGER,       "- trigger"                     },
+  { CA_ARG_INVENTORY_RM_ACTION,                "- action"                      },
+  { CA_ARG_INVENTORY_RM_FIRST,         "- first"                       },
+  { CA_ARG_INVENTORY_RM_LAST,          "- last"                        },
+  { CA_ARG_INVENTORY_RM_ALL,           "- all"                         },
+  { CA_ARG_UNDEFINED,                  " "                             },
+  { CA_ARG_INVENTORY_RESET,            "reset"                         },
+
+  { -1,                                        NULL                            }
 };
 
 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
 {
-  { -1,                                NULL                            }
+  { -1,                                        NULL                            }
 };
 
 static struct ValueTextInfo options_group_choice_mode[] =
 {
-  { ANIM_RANDOM,               "random"                        },
-  { ANIM_LOOP,                 "loop"                          },
-  { ANIM_LINEAR,               "linear"                        },
-  { ANIM_PINGPONG,             "pingpong"                      },
-  { ANIM_PINGPONG2,            "pingpong 2"                    },
+  { ANIM_RANDOM,                       "random"                        },
+  { ANIM_LOOP,                         "loop"                          },
+  { ANIM_LINEAR,                       "linear"                        },
+  { ANIM_PINGPONG,                     "pingpong"                      },
+  { ANIM_PINGPONG2,                    "pingpong 2"                    },
+  { ANIM_LEVEL_NR,                     "level number"                  },
+
+  { -1,                                        NULL                            }
+};
+
+static struct ValueTextInfo options_bd_scheduling_type[] =
+{
+  { GD_SCHEDULING_MILLISECONDS,                "Milliseconds"                  },
+  { GD_SCHEDULING_BD1,                 "BD1"                           },
+  { GD_SCHEDULING_BD2,                 "BD2"                           },
+  { GD_SCHEDULING_PLCK,                        "Construction Kit"              },
+  { GD_SCHEDULING_CRDR,                        "Crazy Dream 7"                 },
+  { GD_SCHEDULING_BD1_ATARI,           "Atari BD1"                     },
+  { GD_SCHEDULING_BD2_PLCK_ATARI,      "Atari BD2 / PLCK"              },
+
+  { -1,                                          NULL                          }
+};
+
+static struct ValueTextInfo options_bd_color_type[] =
+{
+  { GD_COLOR_TYPE_RGB,                 "RGB colors"                    },
+  { GD_COLOR_TYPE_C64,                 "C64 colors"                    },
+  { GD_COLOR_TYPE_C64DTV,              "C64DTV colors"                 },
+  { GD_COLOR_TYPE_ATARI,               "Atari colors"                  },
+
+  { -1,                                          NULL                          }
+};
 
-  { -1,                                NULL                            }
+static struct ValueTextInfo options_bd_color_c64_name[] =
+{
+  { GD_COLOR_INDEX_BLACK,              "Black"                         },
+  { GD_COLOR_INDEX_WHITE,              "White"                         },
+  { GD_COLOR_INDEX_RED,                        "Red"                           },
+  { GD_COLOR_INDEX_CYAN,               "Cyan"                          },
+  { GD_COLOR_INDEX_PURPLE,             "Purple"                        },
+  { GD_COLOR_INDEX_GREEN,              "Green"                         },
+  { GD_COLOR_INDEX_BLUE,               "Blue"                          },
+  { GD_COLOR_INDEX_YELLOW,             "Yellow"                        },
+  { GD_COLOR_INDEX_ORANGE,             "Orange"                        },
+  { GD_COLOR_INDEX_BROWN,              "Brown"                         },
+  { GD_COLOR_INDEX_LIGHTRED,           "Light red"                     },
+  { GD_COLOR_INDEX_GRAY1,              "Dark gray"                     },
+  { GD_COLOR_INDEX_GRAY2,              "Gray"                          },
+  { GD_COLOR_INDEX_LIGHTGREEN,         "Light green"                   },
+  { GD_COLOR_INDEX_LIGHTBLUE,          "Light blue"                    },
+  { GD_COLOR_INDEX_GRAY3,              "Light gray"                    },
+
+  { -1,                                          NULL                          }
 };
 
 static struct ValueTextInfo *action_arg_modes[] =
@@ -2486,6 +3045,7 @@ action_arg_options[] =
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int gadget_id_align;
@@ -2498,275 +3058,413 @@ static struct
   // ---------- level and editor settings -------------------------------------
 
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(8),
-    GADGET_ID_TIME_OR_STEPS,           GADGET_ID_LEVEL_TIMELIMIT_UP,
+    ED_SELECTBOX_ID_TIME_OR_STEPS,
+    -1,                                                ED_LEVEL_SETTINGS_YPOS(8),
+    GADGET_ID_TIME_OR_STEPS,                   GADGET_ID_LEVEL_TIMELIMIT_UP,
     -1,
     options_time_or_steps,
     &level.use_step_counter,
-    NULL, NULL, "(0 => no limit)",     "time or step limit"
+    NULL, NULL, "(0 => no limit)",             "Select time or step limit"
   },
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(10),
-    GADGET_ID_TIME_SCORE_BASE,         GADGET_ID_LEVEL_TIMESCORE_UP,
+    ED_SELECTBOX_ID_TIME_SCORE_BASE,
+    -1,                                                ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_TIME_SCORE_BASE,                 GADGET_ID_LEVEL_TIMESCORE_UP,
     -1,
     options_time_score_base,
     &level.time_score_base,
-    NULL, NULL, NULL,                  "time score for 1 or 10 seconds/steps"
+    NULL, NULL, NULL,                          "Select time score for 1 or 10 seconds/steps"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(12),
-    GADGET_ID_GAME_ENGINE_TYPE,                GADGET_ID_NONE,
+    ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(12),
+    GADGET_ID_GAME_ENGINE_TYPE,                        GADGET_ID_NONE,
     -1,
     options_game_engine_type,
     &level.game_engine_type,
-    NULL, "game engine:", NULL,                "game engine"
+    NULL, "Game engine:", NULL,                        "Select game engine"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(10),
-    GADGET_ID_LEVELSET_SAVE_MODE,      GADGET_ID_NONE,
+    ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_LEVELSET_SAVE_MODE,              GADGET_ID_NONE,
     -1,
     options_levelset_save_mode,
     &levelset_save_mode,
-    "Action:", NULL, NULL,             "action when saving level set"
+    "Action:", NULL, NULL,                     "Select action when saving level set"
+  },
+
+  // ---------- engine settings: config ---------------------------------------
+
+  {
+    ED_SELECTBOX_ID_BD_SCHEDULING_TYPE,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(1),
+    GADGET_ID_BD_SCHEDULING_TYPE,              GADGET_ID_NONE,
+    -1,
+    options_bd_scheduling_type,
+    &level.bd_scheduling_type,
+    NULL, "Scheduling type:", NULL,            "Select level timing"
+  },
+
+  // ---------- engine settings: colors ---------------------------------------
+
+  {
+    ED_SELECTBOX_ID_BD_COLOR_TYPE,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(0),
+    GADGET_ID_BD_COLOR_TYPE,                   GADGET_ID_NONE,
+    -1,
+    options_bd_color_type,
+    &level.bd_color_type,
+    "Boulder Dash level colors:",
+    "Color palette type:", NULL,               "Select color palette type"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_B,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(1),
+    GADGET_ID_BD_COLOR_C64_B,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[0],
+    NULL, "Border color:      ", NULL,         "Select border color (not used)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_0,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(2),
+    GADGET_ID_BD_COLOR_C64_0,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[1],
+    NULL, "Background color:  ", NULL,         "Select background color (C64 graphics)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_1,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(3),
+    GADGET_ID_BD_COLOR_C64_1,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[2],
+    NULL, "Sand color:        ", NULL,         "Select sand color (C64 graphics)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_2,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(4),
+    GADGET_ID_BD_COLOR_C64_2,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[3],
+    NULL, "Steel wall color:  ", NULL,         "Select steel wall color (C64 graphics)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_3,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(5),
+    GADGET_ID_BD_COLOR_C64_3,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[4],
+    NULL, "Wall color:        ", NULL,         "Select wall color (C64 graphics)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_4,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(6),
+    GADGET_ID_BD_COLOR_C64_4,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[5],
+    NULL, "Amoeba color:      ", NULL,         "Select amoeba color (C64 graphics)"
+  },
+  {
+    ED_SELECTBOX_ID_BD_COLOR_C64_5,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(7),
+    GADGET_ID_BD_COLOR_C64_5,                  GADGET_ID_NONE,
+    -1,
+    options_bd_color_c64_name,
+    &bd_color_c64[6],
+    NULL, "Slime color:       ", NULL,         "Select slime color (C64 graphics)"
   },
 
   // ---------- element settings: configure (several elements) ----------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_WIND_DIRECTION,          GADGET_ID_NONE,
+    ED_SELECTBOX_ID_WIND_DIRECTION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_WIND_DIRECTION,                  GADGET_ID_NONE,
     -1,
     options_wind_direction,
     &level.wind_direction_initial,
-    NULL, "initial wind direction:", NULL,     "initial wind direction"
+    NULL, "Initial wind direction:", NULL,     "Select initial wind direction"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(7),
-    GADGET_ID_PLAYER_SPEED,            GADGET_ID_NONE,
+    ED_SELECTBOX_ID_PLAYER_SPEED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(7),
+    GADGET_ID_PLAYER_SPEED,                    GADGET_ID_NONE,
     -1,
     options_player_speed,
     &level.initial_player_stepsize[0],
-    NULL, "initial player speed:", NULL,       "initial player speed"
+    NULL, "Initial player speed:", NULL,       "Select initial player speed"
+  },
+  {
+    ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_GRAVITY_DIRECTION,            GADGET_ID_NONE,
+    -1,
+    options_bd_gravity_direction,
+    &level.bd_gravity_direction,
+    NULL, "Gravity direction:", NULL,          "Select initial gravity direction"
+  },
+  {
+    ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_MM_BALL_CHOICE_MODE,             GADGET_ID_NONE,
+    -1,
+    options_group_choice_mode,
+    &level.mm_ball_choice_mode,
+    NULL, "Choice type:", NULL,                        "Select type of content choice"
   },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CUSTOM_ACCESS_TYPE,      GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_ACCESS_TYPE,              GADGET_ID_NONE,
     -1,
     options_access_type,
     &custom_element.access_type,
-    NULL, NULL, NULL,                  "type of access to this field"
+    NULL, NULL, NULL,                          "Select type of access to this field"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CUSTOM_ACCESS_LAYER,     GADGET_ID_CUSTOM_ACCESS_TYPE,
+    ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_ACCESS_LAYER,             GADGET_ID_CUSTOM_ACCESS_TYPE,
     -1,
     options_access_layer,
     &custom_element.access_layer,
-    NULL, NULL, NULL,                  "layer of access for this field"
+    NULL, NULL, NULL,                          "Select layer of access for this field"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CUSTOM_ACCESS_PROTECTED, GADGET_ID_CUSTOM_ACCESS_LAYER,
+    ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_ACCESS_PROTECTED,         GADGET_ID_CUSTOM_ACCESS_LAYER,
     -1,
     options_access_protected,
     &custom_element.access_protected,
-    NULL, NULL, NULL,                  "protected access for this field"
+    NULL, NULL, NULL,                          "Select protected access for this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_CUSTOM_ACCESS_DIRECTION, GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_CUSTOM_ACCESS_DIRECTION,         GADGET_ID_NONE,
     -1,
     options_access_direction,
     &custom_element.access_direction,
-    NULL, "from", NULL,                        "access direction for this field"
+    NULL, "from", NULL,                                "Select access direction for this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_CUSTOM_WALK_TO_ACTION,   GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_CUSTOM_WALK_TO_ACTION,           GADGET_ID_NONE,
     -1,
     options_walk_to_action,
     &custom_element.walk_to_action,
-    NULL, NULL, NULL,                  "diggable/collectible/pushable"
+    NULL, NULL, NULL,                          "Select diggable/collectible/pushable"
   },
 
   // ---------- element settings: configure 2 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_CUSTOM_MOVE_PATTERN,     GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_MOVE_PATTERN,             GADGET_ID_NONE,
     -1,
     options_move_pattern,
     &custom_element.move_pattern,
-    NULL, "can move", NULL,            "element move pattern"
+    NULL, "Can move", NULL,                    "Select element move pattern"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CUSTOM_MOVE_DIRECTION,   GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_MOVE_DIRECTION,           GADGET_ID_NONE,
     -1,
     options_move_direction,
     &custom_element.move_direction_initial,
-    NULL, "starts moving", NULL,       "initial element move direction"
+    NULL, "Starts moving", NULL,               "Select initial element move direction"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_CUSTOM_MOVE_STEPSIZE,    GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_CUSTOM_MOVE_STEPSIZE,            GADGET_ID_NONE,
     -1,
     options_move_stepsize,
     &custom_element.move_stepsize,
-    NULL, "move/fall speed", NULL,     "speed of element movement"
+    NULL, "Move/fall speed", NULL,             "Select speed of element movement"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,  GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,          GADGET_ID_NONE,
     -1,
     options_move_leave_type,
     &custom_element.move_leave_type,
     // left text with leading spaces to place gadget next to "can dig" gadget
     // (needed because drawing area gadgets created after selectbox gadgets)
-    // NULL, "can dig:    can", ":",   "leave behind or change element"
-    NULL, "            can", ":",      "leave behind or change element"
+    // NULL, "can dig:    can", ":",           "leave behind or change element"
+    NULL, "            Can", ":",              "Select leave behind or change element"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
+    ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_CUSTOM_SMASH_TARGETS,            GADGET_ID_CUSTOM_CAN_SMASH,
     -1,
     options_smash_targets,
     &custom_element.smash_targets,
-    NULL, "can smash", NULL,           "elements that can be smashed"
+    NULL, "Can smash", NULL,                   "Select elements that can be smashed"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
-    GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_SLIPPERY_TYPE,            GADGET_ID_NONE,
     -1,
     options_slippery_type,
     &custom_element.slippery_type,
-    NULL, "slippery", NULL,            "where other elements fall down"
+    NULL, "Slippery", NULL,                    "Select where other elements fall down"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(10),
-    GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_DEADLINESS,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_DEADLINESS,               GADGET_ID_NONE,
     -1,
     options_deadliness,
     &custom_element.deadliness,
-    NULL, "deadly when", NULL,         "deadliness of element"
+    NULL, "Deadly when", NULL,                 "Select deadliness of element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(11),
-    GADGET_ID_CUSTOM_EXPLOSION_TYPE,   GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_CUSTOM_EXPLOSION_TYPE,           GADGET_ID_NONE,
     -1,
     options_explosion_type,
     &custom_element.explosion_type,
-    NULL, "can explode", NULL,         "explosion type"
+    NULL, "Can explode", NULL,                 "Select explosion type"
   },
 
   // ---------- element settings: advanced (custom elements) ------------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_CHANGE_TIME_UNITS,       GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_TIME_UNITS,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_CHANGE_TIME_UNITS,               GADGET_ID_NONE,
     -1,
     options_time_units,
     &custom_element_change.delay_frames,
-    NULL, "delay time given in", NULL, "delay time units for change"
+    NULL, "Delay time given in", NULL,         "Select delay time units for change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_CHANGE_DIRECT_ACTION,    GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_CHANGE_DIRECT_ACTION,            GADGET_ID_NONE,
     -1,
     options_change_direct_action,
     &custom_element_change.direct_action,
-    NULL, NULL, NULL,                  "type of direct action"
+    NULL, NULL, NULL,                          "Select type of direct action"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(5),
-    GADGET_ID_CHANGE_OTHER_ACTION,     GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_OTHER_ACTION,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_CHANGE_OTHER_ACTION,             GADGET_ID_NONE,
     -1,
     options_change_other_action,
     &custom_element_change.other_action,
-    NULL, NULL, "element:",            "type of other element action"
+    NULL, NULL, "element:",                    "Select type of other element action"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(6),
-    GADGET_ID_CHANGE_SIDE,             GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_SIDE,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(6),
+    GADGET_ID_CHANGE_SIDE,                     GADGET_ID_NONE,
     -1,
     options_change_trigger_side,
     &custom_element_change.trigger_side,
-    NULL, "at", "side",                        "element side triggering change"
+    NULL, "at", "side",                                "Select element side triggering change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(7),
-    GADGET_ID_CHANGE_PLAYER,           GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_PLAYER,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(7),
+    GADGET_ID_CHANGE_PLAYER,                   GADGET_ID_NONE,
     -1,
     options_change_trigger_player,
     &custom_element_change.trigger_player,
-    NULL, "player:", " ",              "player that causes change"
+    NULL, "Player:", " ",                      "Select player that causes change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(7),
-    GADGET_ID_CHANGE_PAGE,             GADGET_ID_CHANGE_PLAYER,
+    ED_SELECTBOX_ID_CHANGE_PAGE,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(7),
+    GADGET_ID_CHANGE_PAGE,                     GADGET_ID_CHANGE_PLAYER,
     -1,
     options_change_trigger_page,
     &custom_element_change.trigger_page,
-    NULL, "page:", NULL,               "change page that causes change"
+    NULL, "Page:", NULL,                       "Select change page that causes change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(10),
-    GADGET_ID_CHANGE_REPLACE_WHEN,     GADGET_ID_NONE,
+    ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(10),
+    GADGET_ID_CHANGE_REPLACE_WHEN,             GADGET_ID_NONE,
     -1,
     options_change_replace_when,
     &custom_element_change.replace_when,
-    NULL, "replace when", NULL,                "which elements can be replaced"
+    NULL, "Replace when", NULL,                        "Select which elements can be replaced"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
-    GADGET_ID_ACTION_TYPE,             GADGET_ID_NONE,
+    ED_SELECTBOX_ID_ACTION_TYPE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_TYPE,                     GADGET_ID_NONE,
     15,
     options_action_type,
     &custom_element_change.action_type,
-    NULL, NULL, NULL,                  "action on specified condition"
+    NULL, NULL, NULL,                          "Select action on specified condition"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(13),
-    GADGET_ID_ACTION_MODE,             GADGET_ID_ACTION_TYPE,
+    ED_SELECTBOX_ID_ACTION_MODE,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_MODE,                     GADGET_ID_ACTION_TYPE,
     -1,
     options_action_mode_none,
     &custom_element_change.action_mode,
-    NULL, NULL, NULL,                  "action operator"
+    NULL, NULL, NULL,                          "Select action operator"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(13),
-    GADGET_ID_ACTION_ARG,              GADGET_ID_ACTION_MODE,
+    ED_SELECTBOX_ID_ACTION_ARG,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_ARG,                      GADGET_ID_ACTION_MODE,
     -1,
     options_action_arg_none,
     &custom_element_change.action_arg,
-    NULL, NULL, NULL,                  "action parameter"
+    NULL, NULL, NULL,                          "Select action parameter"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_SELECT_CHANGE_PAGE,      GADGET_ID_NONE,
+    ED_SELECTBOX_ID_SELECT_CHANGE_PAGE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_SELECT_CHANGE_PAGE,              GADGET_ID_NONE,
     3,
     options_change_page,
     &custom_element.current_change_page,
-    NULL, NULL, NULL,                  "element change page"
+    NULL, NULL, NULL,                          "Select element change page"
   },
 
   // ---------- element settings: configure (group elements) ------------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_GROUP_CHOICE_MODE,       GADGET_ID_NONE,
+    ED_SELECTBOX_ID_GROUP_CHOICE_MODE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_GROUP_CHOICE_MODE,               GADGET_ID_NONE,
     -1,
     options_group_choice_mode,
     &group_element_info.choice_mode,
-    NULL, "choice type:", NULL,                "type of group element choice"
+    NULL, "Choice type:", NULL,                        "Select type of group element choice"
   },
 };
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int gadget_id_align;
@@ -2778,98 +3476,146 @@ static struct
   // ---------- level and editor settings (tabs) ------------------------------
 
   {
-    ED_LEVEL_TABS_XPOS(0),             ED_LEVEL_TABS_YPOS(0),
-    GADGET_ID_LEVELINFO_LEVEL,         GADGET_ID_NONE,
-    8,                                 "Level",
-    NULL, NULL, NULL,                  "Configure level properties"
+    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
+    ED_LEVEL_TABS_XPOS(0),                     ED_LEVEL_TABS_YPOS(0),
+    GADGET_ID_LEVELCONFIG_LEVEL,               GADGET_ID_NONE,
+    8,                                         "Level",
+    NULL, NULL, NULL,                          "Configure level settings"
+  },
+  {
+    ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
+    -1,                                                -1,
+    GADGET_ID_LEVELCONFIG_LEVELSET,            GADGET_ID_LEVELCONFIG_LEVEL,
+    8,                                         "Levelset",
+    NULL, NULL, NULL,                          "Update this or create new level set"
+  },
+  {
+    ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
+    -1,                                                -1,
+    GADGET_ID_LEVELCONFIG_EDITOR,              GADGET_ID_LEVELCONFIG_LEVELSET,
+    8,                                         "Editor",
+    NULL, NULL, NULL,                          "Configure editor settings"
+  },
+  {
+    ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE,
+    -1,                                                -1,
+    GADGET_ID_LEVELCONFIG_ENGINE,              GADGET_ID_LEVELCONFIG_EDITOR,
+    8,                                         "Engine",
+    NULL, NULL, NULL,                          "Configure game engine settings"
   },
+
+  // ---------- engine settings (tabs) ----------------------------------------
+
   {
-    -1,                                        -1,
-    GADGET_ID_LEVELINFO_LEVELSET,      GADGET_ID_LEVELINFO_LEVEL,
-    8,                                 "Levelset",
-    NULL, NULL, NULL,                  "Update this or create new level set"
+    ED_TEXTBUTTON_ID_ENGINECONFIG_CONFIG,
+    ED_ENGINE_TABS_XPOS(0),                    ED_ENGINE_TABS_YPOS(0),
+    GADGET_ID_ENGINECONFIG_CONFIG,             GADGET_ID_NONE,
+    8,                                         "Config",
+    NULL, NULL, NULL,                          "Configure game engine settings"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_LEVELINFO_EDITOR,                GADGET_ID_LEVELINFO_LEVELSET,
-    8,                                 "Editor",
-    NULL, NULL, NULL,                  "Configure editor properties"
+    ED_TEXTBUTTON_ID_ENGINECONFIG_COLORS,
+    -1,                                                -1,
+    GADGET_ID_ENGINECONFIG_COLORS,             GADGET_ID_ENGINECONFIG_CONFIG,
+    8,                                         "Colors",
+    NULL, NULL, NULL,                          "Configure level colors"
   },
 
   // ---------- element settings (tabs) ---------------------------------------
 
   {
-    ED_ELEMENT_TABS_XPOS(0),           ED_ELEMENT_TABS_YPOS(0),
-    GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
-    8,                                 "Info",
-    NULL, NULL, NULL,                  "Show information about element"
+    ED_TEXTBUTTON_ID_PROPERTIES_INFO,
+    ED_ELEMENT_TABS_XPOS(0),                   ED_ELEMENT_TABS_YPOS(0),
+    GADGET_ID_PROPERTIES_INFO,                 GADGET_ID_NONE,
+    8,                                         "Info",
+    NULL, NULL, NULL,                          "Show information about element"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_PROPERTIES_CONFIG,       GADGET_ID_PROPERTIES_INFO,
-    8,                                 "Config",
-    NULL, NULL, NULL,                  "Configure element properties"
+    ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
+    -1,                                                -1,
+    GADGET_ID_PROPERTIES_CONFIG,               GADGET_ID_PROPERTIES_INFO,
+    8,                                         "Config",
+    NULL, NULL, NULL,                          "Configure element properties"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_PROPERTIES_CONFIG_1,     GADGET_ID_PROPERTIES_INFO,
-    8,                                 "Config 1",
-    NULL, NULL, NULL,                  "Configure element properties, part 1"
+    ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
+    -1,                                                -1,
+    GADGET_ID_PROPERTIES_CONFIG_1,             GADGET_ID_PROPERTIES_INFO,
+    8,                                         "Config 1",
+    NULL, NULL, NULL,                          "Configure element properties, part 1"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_PROPERTIES_CONFIG_2,     GADGET_ID_PROPERTIES_CONFIG_1,
-    8,                                 "Config 2",
-    NULL, NULL, NULL,                  "Configure element properties, part 2"
+    ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2,
+    -1,                                                -1,
+    GADGET_ID_PROPERTIES_CONFIG_2,             GADGET_ID_PROPERTIES_CONFIG_1,
+    8,                                         "Config 2",
+    NULL, NULL, NULL,                          "Configure element properties, part 2"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_PROPERTIES_CHANGE,       GADGET_ID_PROPERTIES_CONFIG_2,
-    8,                                 "Change",
-    NULL, NULL, NULL,                  "Configure custom element change pages"
+    ED_TEXTBUTTON_ID_PROPERTIES_CHANGE,
+    -1,                                                -1,
+    GADGET_ID_PROPERTIES_CHANGE,               GADGET_ID_PROPERTIES_CONFIG_2,
+    8,                                         "Change",
+    NULL, NULL, NULL,                          "Configure custom element change pages"
   },
 
   // ---------- level and editor settings (buttons) ---------------------------
 
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(10),
-    GADGET_ID_SAVE_LEVELSET,           GADGET_ID_LEVELSET_SAVE_MODE,
-    -1,                                        "Save",
-    NULL, NULL, NULL,                  "Update or create level set"
+    ED_TEXTBUTTON_ID_SAVE_LEVELSET,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_SAVE_LEVELSET,                   GADGET_ID_LEVELSET_SAVE_MODE,
+    -1,                                                "Save",
+    NULL, NULL, NULL,                          "Update or create level set"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(6),
-    GADGET_ID_SAVE_AS_TEMPLATE_2,      GADGET_ID_NONE,
-    -1,                                        "Save",
-    NULL, NULL,                                "this level as level template",
+    ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(6),
+    GADGET_ID_SAVE_AS_TEMPLATE_2,              GADGET_ID_NONE,
+    -1,                                                "Save",
+    NULL, NULL,                                        "this level as level template",
     "Save current settings as new template"
   },
 
   // ---------- element settings (buttons) ------------------------------------
 
   {
-    -1,                                        -1,
-    GADGET_ID_SAVE_AS_TEMPLATE_1,      GADGET_ID_CUSTOM_USE_TEMPLATE_1,
-    -1,                                        "Save",
-    NULL, " ",                         "As Template",
+    ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1,
+    -1,                                                -1,
+    GADGET_ID_SAVE_AS_TEMPLATE_1,              GADGET_ID_CUSTOM_USE_TEMPLATE_1,
+    -1,                                                "Save",
+    NULL, " ",                                 "As Template",
     "Save current settings as new template"
   },
   {
-    -1,                                        -1,
-    GADGET_ID_ADD_CHANGE_PAGE,         GADGET_ID_PASTE_CHANGE_PAGE,
-    -1,                                        "New",
-    NULL, NULL, NULL,                  "Add new change page"
+    ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE,
+    -1,                                                -1,
+    GADGET_ID_ADD_CHANGE_PAGE,                 GADGET_ID_PASTE_CHANGE_PAGE,
+    -1,                                                "New",
+    NULL, NULL, NULL,                          "Add new change page"
+  },
+  {
+    ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE,
+    -1,                                                -1,
+    GADGET_ID_DEL_CHANGE_PAGE,                 GADGET_ID_ADD_CHANGE_PAGE,
+    -1,                                                "Delete",
+    NULL, NULL, NULL,                          "Delete current change page"
   },
+
+  // ---------- engine settings (buttons) -------------------------------------
+
   {
-    -1,                                        -1,
-    GADGET_ID_DEL_CHANGE_PAGE,         GADGET_ID_ADD_CHANGE_PAGE,
-    -1,                                        "Delete",
-    NULL, NULL, NULL,                  "Delete current change page"
+    ED_TEXTBUTTON_ID_BD_SET_RANDOM_COLORS,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(8),
+    GADGET_ID_BD_SET_RANDOM_COLORS,            GADGET_ID_NONE,
+    -1,                                                "Set random colors",
+    NULL, NULL, NULL,                          "Create and set random level colors"
   },
 };
 
 static struct
 {
+  int gadget_type_id;
   int graphic;
   int x, y;
   int gadget_id;
@@ -2878,28 +3624,32 @@ static struct
 } graphicbutton_info[ED_NUM_GRAPHICBUTTONS] =
 {
   {
+    ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE,
     IMG_EDITOR_COUNTER_DOWN,
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_PREV_CHANGE_PAGE,                GADGET_ID_NONE,
-    NULL, NULL,                                "select previous change page"
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_PREV_CHANGE_PAGE,                        GADGET_ID_NONE,
+    NULL, NULL,                                        "Select previous change page"
   },
   {
+    ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE,
     IMG_EDITOR_COUNTER_UP,
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_NEXT_CHANGE_PAGE,                GADGET_ID_SELECT_CHANGE_PAGE,
-    NULL, "change page",               "select next change page"
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_NEXT_CHANGE_PAGE,                        GADGET_ID_SELECT_CHANGE_PAGE,
+    NULL, "Change page",                       "Select next change page"
   },
   {
+    ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE,
     IMG_GFX_EDITOR_BUTTON_CP_COPY,
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_COPY_CHANGE_PAGE,                GADGET_ID_NEXT_CHANGE_PAGE,
-    " ", NULL,                         "copy settings from this change page"
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_COPY_CHANGE_PAGE,                        GADGET_ID_NEXT_CHANGE_PAGE,
+    " ", NULL,                                 "Copy settings from this change page"
   },
   {
+    ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE,
     IMG_GFX_EDITOR_BUTTON_CP_PASTE,
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_PASTE_CHANGE_PAGE,       GADGET_ID_COPY_CHANGE_PAGE,
-    NULL, NULL,                                "paste settings to this change page"
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_PASTE_CHANGE_PAGE,               GADGET_ID_COPY_CHANGE_PAGE,
+    NULL, NULL,                                        "Paste settings to this change page"
   },
 };
 
@@ -2910,40 +3660,47 @@ static struct
 
 static struct
 {
+  int gadget_type_id;
   int graphic;
   int gadget_id;
   char *infotext;
 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
 {
   {
+    ED_SCROLLBUTTON_ID_AREA_UP,
     IMG_EDITOR_PLAYFIELD_SCROLL_UP,
     GADGET_ID_SCROLL_UP,
-    "scroll level editing area up"
+    "Scroll level editing area up"
   },
   {
+    ED_SCROLLBUTTON_ID_AREA_DOWN,
     IMG_EDITOR_PLAYFIELD_SCROLL_DOWN,
     GADGET_ID_SCROLL_DOWN,
-    "scroll level editing area down"
+    "Scroll level editing area down"
   },
   {
+    ED_SCROLLBUTTON_ID_AREA_LEFT,
     IMG_EDITOR_PLAYFIELD_SCROLL_LEFT,
     GADGET_ID_SCROLL_LEFT,
-    "scroll level editing area left"
+    "Scroll level editing area left"
   },
   {
+    ED_SCROLLBUTTON_ID_AREA_RIGHT,
     IMG_EDITOR_PLAYFIELD_SCROLL_RIGHT,
     GADGET_ID_SCROLL_RIGHT,
-    "scroll level editing area right"
+    "Scroll level editing area right"
   },
   {
+    ED_SCROLLBUTTON_ID_LIST_UP,
     IMG_EDITOR_PALETTE_SCROLL_UP,
     GADGET_ID_SCROLL_LIST_UP,
-    "scroll element list up ('Page Up')"
+    "Scroll element list up ('Page Up')"
   },
   {
+    ED_SCROLLBUTTON_ID_LIST_DOWN,
     IMG_EDITOR_PALETTE_SCROLL_DOWN,
     GADGET_ID_SCROLL_LIST_DOWN,
-    "scroll element list down ('Page Down')"
+    "Scroll element list down ('Page Down')"
   },
 };
 
@@ -2957,6 +3714,7 @@ static struct
 
 static struct
 {
+  int gadget_type_id;
   int graphic;
   int type;
   int gadget_id;
@@ -2964,28 +3722,32 @@ static struct
 } scrollbar_info[ED_NUM_SCROLLBARS] =
 {
   {
+    ED_SCROLLBAR_ID_AREA_HORIZONTAL,
     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_HORIZONTAL,
     GADGET_ID_SCROLL_HORIZONTAL,
-    "scroll level editing area horizontally"
+    "Scroll level editing area horizontally"
   },
   {
+    ED_SCROLLBAR_ID_AREA_VERTICAL,
     IMG_EDITOR_PLAYFIELD_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_VERTICAL,
-    "scroll level editing area vertically"
+    "Scroll level editing area vertically"
   },
   {
+    ED_SCROLLBAR_ID_LIST_VERTICAL,
     IMG_EDITOR_PALETTE_SCROLLBAR,
     GD_TYPE_SCROLLBAR_VERTICAL,
     GADGET_ID_SCROLL_LIST_VERTICAL,
-    "scroll element list vertically"
+    "Scroll element list vertically"
   }
 };
 
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int gadget_id_align;
@@ -2996,23 +3758,26 @@ static struct
 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
 {
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(0),
-    GADGET_ID_RANDOM_PERCENTAGE,       GADGET_ID_LEVEL_RANDOM_UP,
+    ED_RADIOBUTTON_ID_PERCENTAGE,
+    -1,                                                ED_LEVEL_SETTINGS_YPOS(0),
+    GADGET_ID_RANDOM_PERCENTAGE,               GADGET_ID_LEVEL_RANDOM_UP,
     RADIO_NR_RANDOM_ELEMENTS,
-    &random_placement_method,          RANDOM_USE_PERCENTAGE,
-    " ", "percentage",                 "use percentage for random elements"
+    &random_placement_method,                  RANDOM_USE_PERCENTAGE,
+    " ", "percentage",                         "Use percentage for random elements"
   },
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(0),
-    GADGET_ID_RANDOM_QUANTITY,         GADGET_ID_RANDOM_PERCENTAGE,
+    ED_RADIOBUTTON_ID_QUANTITY,
+    -1,                                                ED_LEVEL_SETTINGS_YPOS(0),
+    GADGET_ID_RANDOM_QUANTITY,                 GADGET_ID_RANDOM_PERCENTAGE,
     RADIO_NR_RANDOM_ELEMENTS,
-    &random_placement_method,          RANDOM_USE_QUANTITY,
-    " ", "quantity",                   "use quantity for random elements"
+    &random_placement_method,                  RANDOM_USE_QUANTITY,
+    " ", "quantity",                           "Use quantity for random elements"
   }
 };
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int gadget_id;
   int gadget_id_align;
@@ -3023,518 +3788,854 @@ static struct
   // ---------- level and editor settings -------------------------------------
 
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(6),
-    GADGET_ID_AUTO_COUNT_GEMS,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(6),
+    GADGET_ID_AUTO_COUNT_GEMS,                 GADGET_ID_NONE,
     &level.auto_count_gems,
     NULL, NULL,
-    "automatically count gems needed", "set counter to number of gems"
+    "Automatically count gems needed",         "Set counter to number of gems"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
-    GADGET_ID_RATE_TIME_OVER_SCORE,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(11),
+    GADGET_ID_RATE_TIME_OVER_SCORE,            GADGET_ID_NONE,
     &level.rate_time_over_score,
     NULL, NULL,
-    "rate time/steps used over score", "sort high scores by playing time/steps"
+    "Rate time/steps used over score",         "Sort high scores by playing time/steps"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(7),
-    GADGET_ID_USE_LEVELSET_ARTWORK,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(7),
+    GADGET_ID_USE_LEVELSET_ARTWORK,            GADGET_ID_NONE,
     &levelset_use_levelset_artwork,
     NULL, NULL,
-    "use current custom artwork",      "use custom artwork of this level set"
+    "Use current custom artwork",              "Use custom artwork of this level set"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(8),
-    GADGET_ID_COPY_LEVEL_TEMPLATE,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(8),
+    GADGET_ID_COPY_LEVEL_TEMPLATE,             GADGET_ID_NONE,
     &levelset_copy_level_template,
     NULL, NULL,
-    "copy current level template",     "copy level template of this level set"
+    "Copy current level template",             "Copy level template of this level set"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(1),
-    GADGET_ID_RANDOM_RESTRICTED,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(1),
+    GADGET_ID_RANDOM_RESTRICTED,               GADGET_ID_NONE,
     &random_placement_background_restricted,
     NULL, NULL,
-    "restrict random placement to:",   "set random placement restriction"
+    "Restrict random placement to:",           "Set random placement restriction"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(4),
-    GADGET_ID_CUSTOM_USE_TEMPLATE_3,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_3,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(4),
+    GADGET_ID_CUSTOM_USE_TEMPLATE_3,           GADGET_ID_NONE,
     &setup.editor.use_template_for_new_levels,
     "Template for new levels and CE/GE:", NULL,
-    "use template for new levels",     "use template for level properties"
+    "Use template for new levels",             "Use template for level properties"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(5),
-    GADGET_ID_CUSTOM_USE_TEMPLATE_2,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_2,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_LEVEL_SETTINGS_YPOS(5),
+    GADGET_ID_CUSTOM_USE_TEMPLATE_2,           GADGET_ID_NONE,
     &level.use_custom_template,
     NULL, NULL,
-    "use template for custom elements",        "use template for custom properties"
+    "Use template for custom elements",                "Use template for custom properties"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_INTERMISSION,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(0),
+    GADGET_ID_BD_INTERMISSION,                 GADGET_ID_NONE,
+    &level.bd_intermission,
+    "Boulder Dash game engine settings:", NULL,
+    "Intermission",                            "Level is an intermission level"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_PAL_TIMING,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(2),
+    GADGET_ID_BD_PAL_TIMING,                   GADGET_ID_NONE,
+    &level.bd_pal_timing,
+    NULL, NULL,
+    "PAL timing",                              "Use slower timer (like PAL C64)"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_LINE_SHIFTING_BORDERS,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(6),
+    GADGET_ID_BD_LINE_SHIFTING_BORDERS,                GADGET_ID_NONE,
+    &level.bd_line_shifting_borders,
+    "Compatibility settings:", NULL,
+    "Line-shifting borders",                   "Use line-shifting wrap-around"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_SCAN_FIRST_AND_LAST_ROW,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(7),
+    GADGET_ID_BD_SCAN_FIRST_AND_LAST_ROW,      GADGET_ID_NONE,
+    &level.bd_scan_first_and_last_row,
+    NULL, NULL,
+    "Scan first and last row",                 "Also process top/bottom border rows"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_SHORT_EXPLOSIONS,
+    ED_ENGINE_SETTINGS_XPOS(0),                        ED_ENGINE_SETTINGS_YPOS(8),
+    GADGET_ID_BD_SHORT_EXPLOSIONS,             GADGET_ID_NONE,
+    &level.bd_short_explosions,
+    NULL, NULL,
+    "Short explosions",                                "Use four game cycles for explosions"
   },
 
   // ---------- element settings: configure (various elements) ----------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_STICK_ELEMENT,           GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_STICK_ELEMENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_STICK_ELEMENT,                   GADGET_ID_NONE,
     &stick_element_properties_window,
     NULL, NULL,
-    "stick this screen to edit content","stick this screen to edit content"
+    "Stick this screen to edit content",       "Stick this screen to edit content"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_EM_SLIPPERY_GEMS,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_EM_SLIPPERY_GEMS,                        GADGET_ID_NONE,
     &level.em_slippery_gems,
     NULL, NULL,
-    "slip down from certain flat walls","use EM/DC style slipping behaviour"
+    "Slip down from certain flat walls",       "Use EM/DC style slipping behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_EM_EXPLODES_BY_FIRE,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_EM_EXPLODES_BY_FIRE,             GADGET_ID_NONE,
     &level.em_explodes_by_fire,
     NULL, NULL,
-    "explodes with chain reaction",    "use R'n'D style explosion behaviour"
+    "Explodes with chain reaction",            "Use R'n'D style explosion behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_USE_SPRING_BUG,          GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_SPRING_BUG,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_USE_SPRING_BUG,                  GADGET_ID_NONE,
     &level.use_spring_bug,
     NULL, NULL,
-    "use spring pushing bug",          "use odd spring pushing behaviour"
+    "Use spring pushing bug",                  "Use odd spring pushing behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_USE_TIME_ORB_BUG,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_USE_TIME_ORB_BUG,                        GADGET_ID_NONE,
     &level.use_time_orb_bug,
     NULL, NULL,
-    "use time orb bug",                        "use odd time orb behaviour"
+    "Use time orb bug",                                "Use odd time orb behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
-    GADGET_ID_USE_LIFE_BUGS,           GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_USE_LIFE_BUGS,                   GADGET_ID_NONE,
     &level.use_life_bugs,
     NULL, NULL,
-    "use buggy element behaviour",     "use odd (historic) element behaviour"
+    "Use buggy element behaviour",             "Use odd (historic) element behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_RANDOM_BALL_CONTENT,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_RANDOM_BALL_CONTENT,             GADGET_ID_NONE,
     &level.ball_random,
     NULL, NULL,
-    "create single random element",    "only create one element from content"
+    "Create single random element",            "Only create one element from content"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_INITIAL_BALL_ACTIVE,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_INITIAL_BALL_ACTIVE,             GADGET_ID_NONE,
     &level.ball_active_initial,
     NULL, NULL,
-    "magic ball initially activated",  "activate magic ball after level start"
+    "Magic ball initially activated",          "Activate magic ball after level start"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_GROW_INTO_DIGGABLE,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_GROW_INTO_DIGGABLE,              GADGET_ID_NONE,
     &level.grow_into_diggable,
     NULL, NULL,
-    "can grow into anything diggable", "grow into more than just sand"
+    "Can grow into anything diggable",         "Grow into more than just sand"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_SB_FIELDS_NEEDED,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_SB_FIELDS_NEEDED,                        GADGET_ID_NONE,
     &level.sb_fields_needed,
     NULL, NULL,
-    "all fields need to be filled",    "require all SB fields to be solved"
+    "All fields need to be filled",            "Require all SB fields to be solved"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_SB_OBJECTS_NEEDED,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_SB_OBJECTS_NEEDED,               GADGET_ID_NONE,
     &level.sb_objects_needed,
     NULL, NULL,
-    "all objects need to be placed",   "require all SB objects to be solved"
+    "All objects need to be placed",           "Require all SB objects to be solved"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_AUTO_EXIT_SOKOBAN,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_AUTO_EXIT_SOKOBAN,               GADGET_ID_NONE,
     &level.auto_exit_sokoban,
     NULL, NULL,
-    "exit level if all tasks solved",  "automatically finish Sokoban levels"
+    "Exit level if all tasks solved",          "Automatically finish Sokoban levels"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_SOLVED_BY_ONE_PLAYER,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_SOLVED_BY_ONE_PLAYER,            GADGET_ID_NONE,
     &level.solved_by_one_player,
     NULL, NULL,
-    "only one player must enter exit", "level solved by first player in exit"
+    "Only one player must enter exit",         "Level solved by first player in exit"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_FINISH_DIG_COLLECT,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_FINISH_DIG_COLLECT,              GADGET_ID_NONE,
     &level.finish_dig_collect,
     NULL, NULL,
-    "CE action on finished dig/collect", "only finished dig/collect triggers CE"
+    "CE action on finished dig/collect",       "Only finished dig/collect triggers CE"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_KEEP_WALKABLE_CE,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_KEEP_WALKABLE_CE,                        GADGET_ID_NONE,
     &level.keep_walkable_ce,
     NULL, NULL,
-    "keep walkable CE changed to player", "keep CE changing to player if walkable"
+    "Keep walkable CE changed to player",      "Keep CE changing to player if walkable"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
-    GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_CONTINUOUS_SNAPPING,             GADGET_ID_NONE,
     &level.continuous_snapping,
     NULL, NULL,
-    "continuous snapping",             "use snapping without releasing key"
+    "Continuous snapping",                     "Use snapping without releasing key"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_BLOCK_SNAP_FIELD,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_BLOCK_SNAP_FIELD,                        GADGET_ID_NONE,
     &level.block_snap_field,
     NULL, NULL,
-    "block snapped field when snapping", "use snapping delay to show animation"
+    "Block snapped field when snapping",       "Use snapping delay to show animation"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_BLOCK_LAST_FIELD,                GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BLOCK_LAST_FIELD,                        GADGET_ID_NONE,
     &level.block_last_field,
     NULL, NULL,
-    "block last field when moving",    "player blocks last field when moving"
+    "Block last field when moving",            "Player blocks last field when moving"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_SP_BLOCK_LAST_FIELD,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_SP_BLOCK_LAST_FIELD,             GADGET_ID_NONE,
     &level.sp_block_last_field,
     NULL, NULL,
-    "block last field when moving",    "player blocks last field when moving"
+    "Block last field when moving",            "Player blocks last field when moving"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_INSTANT_RELOCATION,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_INSTANT_RELOCATION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_INSTANT_RELOCATION,              GADGET_ID_NONE,
     &level.instant_relocation,
     NULL, NULL,
-    "no scrolling when relocating",    "player gets relocated without delay"
+    "No scrolling when relocating",            "Player gets relocated without delay"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_SHIFTED_RELOCATION,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_SHIFTED_RELOCATION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_SHIFTED_RELOCATION,              GADGET_ID_NONE,
     &level.shifted_relocation,
     NULL, NULL,
-    "no centering when relocating",    "level not centered after relocation"
+    "No centering when relocating",            "Level not centered after relocation"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
-    GADGET_ID_LAZY_RELOCATION,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_LAZY_RELOCATION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_LAZY_RELOCATION,                 GADGET_ID_NONE,
     &level.lazy_relocation,
     NULL, NULL,
-    "only redraw off-screen relocation","no redraw if relocation target visible"
+    "Only redraw off-screen relocation",       "No redraw if relocation target visible"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
-    GADGET_ID_USE_START_ELEMENT,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_START_ELEMENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(10),
+    GADGET_ID_USE_START_ELEMENT,               GADGET_ID_NONE,
     &level.use_start_element[0],
     NULL, NULL,
-    "use level start element:",               "start level at this element's position"
+    "Use level start element:",                       "Start level at this element's position"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
-    GADGET_ID_USE_ARTWORK_ELEMENT,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_USE_ARTWORK_ELEMENT,             GADGET_ID_NONE,
     &level.use_artwork_element[0],
     NULL, NULL,
-    "use artwork from element:",       "use player artwork from other element"
+    "Use artwork from element:",               "Use player artwork from other element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(12),
-    GADGET_ID_USE_EXPLOSION_ELEMENT,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(12),
+    GADGET_ID_USE_EXPLOSION_ELEMENT,           GADGET_ID_NONE,
     &level.use_explosion_element[0],
     NULL, NULL,
-    "use explosion from element:",     "use explosion properties from element"
+    "Use explosion from element:",             "Use explosion properties from element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(13),
-    GADGET_ID_INITIAL_GRAVITY,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_INITIAL_GRAVITY,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_INITIAL_GRAVITY,                 GADGET_ID_NONE,
     &level.initial_player_gravity[0],
     NULL, NULL,
-    "use initial gravity",             "set initial player gravity"
+    "Use initial gravity",                     "Set initial player gravity"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_USE_INITIAL_INVENTORY,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_USE_INITIAL_INVENTORY,           GADGET_ID_NONE,
     &level.use_initial_inventory[0],
     NULL, NULL,
-    "use initial inventory:",          "use collected elements on level start"
+    "Use initial inventory:",                  "Use collected elements on level start"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(6),
-    GADGET_ID_CAN_PASS_TO_WALKABLE,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(6),
+    GADGET_ID_CAN_PASS_TO_WALKABLE,            GADGET_ID_NONE,
     &level.can_pass_to_walkable,
     NULL, NULL,
-    "can pass to walkable element",    "player can pass to empty or walkable"
+    "Can pass to walkable element",            "Player can pass to empty or walkable"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_CAN_FALL_INTO_ACID,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_CAN_FALL_INTO_ACID,              GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
     NULL, NULL,
-    "can fall into acid (with gravity)","player can fall into acid pool"
+    "Can fall into acid (with gravity)",       "Player can fall into acid pool"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
-    GADGET_ID_CAN_MOVE_INTO_ACID,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_CAN_MOVE_INTO_ACID,              GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
     NULL, NULL,
-    "can move into acid",              "element can move into acid pool"
+    "Can move into acid",                      "Element can move into acid pool"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_DONT_COLLIDE_WITH,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_DONT_COLLIDE_WITH,               GADGET_ID_NONE,
     &custom_element_properties[EP_DONT_COLLIDE_WITH],
     NULL, NULL,
-    "deadly when colliding with",      "element is deadly when hitting player"
+    "Deadly when colliding with",              "Element is deadly when hitting player"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_DIAGONAL_MOVEMENTS,           GADGET_ID_NONE,
+    &level.bd_diagonal_movements,
+    NULL, NULL,
+    "Can move diagonally",                     "Player can move diagonally"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_TOPMOST_PLAYER_ACTIVE,                GADGET_ID_NONE,
+    &level.bd_topmost_player_active,
+    NULL, NULL,
+    "Topmost player is active",                        "Use first player found on playfield"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET,    GADGET_ID_NONE,
+    &level.bd_push_mega_rock_with_sweet,
+    NULL, NULL,
+    "Mega rocks pushable with sweet",          "Push mega rocks after eating sweet"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,     GADGET_ID_NONE,
+    &level.bd_magic_wall_zero_infinite,
+    NULL, NULL,
+    "Run forever if duration is zero",         "Run infinitely if timer is zero"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,     GADGET_ID_NONE,
+    &level.bd_magic_wall_wait_hatching,
+    NULL, NULL,
+    "Wait for player's birth",                 "Timer start waits for player's birth"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,      GADGET_ID_NONE,
+    &level.bd_magic_wall_stops_amoeba,
+    NULL, NULL,
+    "Stop amoeba and turn to diamonds",                "Activation changes amoeba to diamonds"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,                GADGET_ID_NONE,
+    &level.bd_magic_wall_break_scan,
+    NULL, NULL,
+    "Emulate amoeba bug in BD1",               "Use buggy BD1 behavior"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,     GADGET_ID_NONE,
+    &level.bd_amoeba_wait_for_hatching,
+    NULL, NULL,
+    "Wait for player's birth",                 "Timer start waits for player's birth"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,     GADGET_ID_NONE,
+    &level.bd_amoeba_start_immediately,
+    NULL, NULL,
+    "Start growing immediately",               "Start slow growth time immediately"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,   GADGET_ID_NONE,
+    &level.bd_amoeba_2_explode_by_amoeba,
+    NULL, NULL,
+    "Explodes if touched by amoeba",           "Amoeba 2 explodes if touched by amoeba"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,     GADGET_ID_NONE,
+    &level.bd_voodoo_collects_diamonds,
+    NULL, NULL,
+    "Can collect diamonds",                    "Can collect diamonds for the player"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,     GADGET_ID_NONE,
+    &level.bd_voodoo_hurt_kills_player,
+    NULL, NULL,
+    "Player is killed if hurt",                        "If hurt in any way, player is killed"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BD_VOODOO_DIES_BY_ROCK,          GADGET_ID_NONE,
+    &level.bd_voodoo_dies_by_rock,
+    NULL, NULL,
+    "Killed by falling rock",                  "Can be killed by a falling rock"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,   GADGET_ID_NONE,
+    &level.bd_voodoo_vanish_by_explosion,
+    NULL, NULL,
+    "Disappears in explosions",                        "Can be destroyed by explosions"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_SLIME_IS_PREDICTABLE,         GADGET_ID_NONE,
+    &level.bd_slime_is_predictable,
+    NULL, NULL,
+    "Slime is predictable",                    "Use predictable random numbers"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_CHANGE_EXPANDING_WALL,                GADGET_ID_NONE,
+    &level.bd_change_expanding_wall,
+    NULL, NULL,
+    "Change direction",                                "Switch horizontal/vertical direction"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_REPLICATORS_ACTIVE,           GADGET_ID_NONE,
+    &level.bd_replicators_active,
+    NULL, NULL,
+    "Active at start",                         "Replicators start in active state"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_CONVEYOR_BELTS_ACTIVE,                GADGET_ID_NONE,
+    &level.bd_conveyor_belts_active,
+    NULL, NULL,
+    "Active at start",                         "Conveyor belts start in active state"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_CONVEYOR_BELTS_CHANGED,       GADGET_ID_NONE,
+    &level.bd_conveyor_belts_changed,
+    NULL, NULL,
+    "Change direction",                                "Switch conveyor belt direction"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_WATER_CANNOT_FLOW_DOWN,       GADGET_ID_NONE,
+    &level.bd_water_cannot_flow_down,
+    NULL, NULL,
+    "Does not flow downwards",                 "Water can only flow up, left and right"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_HAMMER_WALLS_REAPPEAR,                GADGET_ID_NONE,
+    &level.bd_hammer_walls_reappear,
+    NULL, NULL,
+    "Hammered walls reappear",                 "Hammered walls reappear after delay"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_INFINITE_ROCKETS,             GADGET_ID_NONE,
+    &level.bd_infinite_rockets,
+    NULL, NULL,
+    "Infinite rockets",                                "Rocket launcher has infinite rockets"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_ENVELOPE_AUTOWRAP,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_CREATURES_START_BACKWARDS,    GADGET_ID_NONE,
+    &level.bd_creatures_start_backwards,
+    NULL, NULL,
+    "Creatures start moving backwards",                "Creatures start in opposite direction"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BD_CREATURES_TURN_ON_HATCHING,   GADGET_ID_NONE,
+    &level.bd_creatures_turn_on_hatching,
+    NULL, NULL,
+    "Creatures auto turn on hatching",         "Creatures change direction on hatching"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_GRAVITY_SWITCH_ACTIVE,                GADGET_ID_NONE,
+    &level.bd_gravity_switch_active,
+    NULL, NULL,
+    "Gravity switch active at start",          "Gravity switch starts in active state"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL,
+    ED_LEVEL_SETTINGS_XPOS(0),                 ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_BD_GRAVITY_AFFECTS_ALL,          GADGET_ID_NONE,
+    &level.bd_gravity_affects_all,
+    NULL, NULL,
+    "Gravity change affects everything",       "Gravity affects all falling objects"
+  },
+  {
+    ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_ENVELOPE_AUTOWRAP,               GADGET_ID_NONE,
     &level.envelope[0].autowrap,
     NULL, NULL,
-    "auto-wrap",                       "automatically wrap envelope text"
+    "Auto-wrap",                               "Automatically wrap envelope text"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_ENVELOPE_CENTERED,       GADGET_ID_ENVELOPE_AUTOWRAP,
+    ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_ENVELOPE_CENTERED,               GADGET_ID_ENVELOPE_AUTOWRAP,
     &level.envelope[0].centered,
     NULL, " ",
-    "centered",                                "automatically center envelope text"
+    "Centered",                                        "Automatically center envelope text"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_MM_LASER_RED,            GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_MM_LASER_RED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_MM_LASER_RED,                    GADGET_ID_NONE,
     &level.mm_laser_red,
-    "choose color components for laser:", NULL,
-    "red",                             "use red color components in laser"
+    "Choose color components for laser:", NULL,
+    "Red",                                     "Use red color components in laser"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_MM_LASER_GREEN,          GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_MM_LASER_GREEN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_MM_LASER_GREEN,                  GADGET_ID_NONE,
     &level.mm_laser_green,
     NULL, NULL,
-    "green",                           "use green color components in laser"
+    "Green",                                   "Use green color components in laser"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_MM_LASER_BLUE,           GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_MM_LASER_BLUE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_MM_LASER_BLUE,                   GADGET_ID_NONE,
     &level.mm_laser_blue,
     NULL, NULL,
-    "blue",                            "use blue color components in laser"
+    "Blue",                                    "Use blue color components in laser"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_DF_LASER_RED,            GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_DF_LASER_RED,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_DF_LASER_RED,                    GADGET_ID_NONE,
     &level.df_laser_red,
-    "choose color components for laser:", NULL,
-    "red",                             "use red color components in laser"
+    "Choose color components for laser:", NULL,
+    "Red",                                     "Use red color components in laser"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_DF_LASER_GREEN,          GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_DF_LASER_GREEN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_DF_LASER_GREEN,                  GADGET_ID_NONE,
     &level.df_laser_green,
     NULL, NULL,
-    "green",                           "use green color components in laser"
+    "Green",                                   "Use green color components in laser"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
-    GADGET_ID_DF_LASER_BLUE,           GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_DF_LASER_BLUE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_DF_LASER_BLUE,                   GADGET_ID_NONE,
     &level.df_laser_blue,
     NULL, NULL,
-    "blue",                            "use blue color components in laser"
+    "Blue",                                    "Use blue color components in laser"
+  },
+  {
+    ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_ROTATE_MM_BALL_CONTENT,          GADGET_ID_NONE,
+    &level.rotate_mm_ball_content,
+    NULL, NULL,
+    "Randomly rotate created content",         "Randomly rotate newly created content"
+  },
+  {
+    ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(6),
+    GADGET_ID_EXPLODE_MM_BALL,                 GADGET_ID_NONE,
+    &level.explode_mm_ball,
+    NULL, NULL,
+    "Explode ball instead of melting",         "Use explosion to release ball content"
   },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_CUSTOM_USE_GRAPHIC,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_USE_GRAPHIC,              GADGET_ID_NONE,
     &custom_element.use_gfx_element,
     NULL, NULL,
-    "use graphic of element:",         "use existing element graphic"
+    "Use graphic of element:",                 "Use existing element graphic"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(14),
-    GADGET_ID_CUSTOM_USE_TEMPLATE_1,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(14),
+    GADGET_ID_CUSTOM_USE_TEMPLATE_1,           GADGET_ID_NONE,
     &level.use_custom_template,
     NULL, NULL,
-    "use template",                    "use template for custom properties"
+    "Use template",                            "Use template for custom properties"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CUSTOM_ACCESSIBLE,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_ACCESSIBLE,               GADGET_ID_NONE,
     &custom_element_properties[EP_ACCESSIBLE],
     NULL, NULL,
-    NULL,                              "player can walk to or pass this field"
+    NULL,                                      "Player can walk to or pass this field"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
-    GADGET_ID_CUSTOM_GRAV_REACHABLE,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_GRAV_REACHABLE,           GADGET_ID_NONE,
     &custom_element_properties[EP_GRAVITY_REACHABLE],
     NULL, NULL,
-    "reachable despite gravity",       "player can walk/dig despite gravity"
+    "Reachable despite gravity",               "Player can walk/dig despite gravity"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
-    GADGET_ID_CUSTOM_USE_LAST_VALUE,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_CUSTOM_USE_LAST_VALUE,           GADGET_ID_NONE,
     &custom_element.use_last_ce_value,
     NULL, NULL,
-    "use last CE value after change",  "use last CE value after change"
+    "Use last CE value after change",          "Use last CE value after change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_CUSTOM_WALK_TO_OBJECT,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_CUSTOM_WALK_TO_OBJECT,           GADGET_ID_NONE,
     &custom_element_properties[EP_WALK_TO_OBJECT],
     NULL, NULL,
-    NULL,                              "player can dig/collect/push element"
+    NULL,                                      "Player can dig/collect/push element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_CUSTOM_INDESTRUCTIBLE,   GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_CUSTOM_INDESTRUCTIBLE,           GADGET_ID_NONE,
     &custom_element_properties[EP_INDESTRUCTIBLE],
     NULL, NULL,
-    "indestructible",                  "element is indestructible"
+    "Indestructible",                          "Element is indestructible"
   },
 
   // ---------- element settings: configure 2 (custom elements) ---------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_CUSTOM_CAN_MOVE,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_CAN_MOVE,                 GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_MOVE],
     NULL, NULL,
-    NULL,                              "element can move with some pattern"
+    NULL,                                      "Element can move with some pattern"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_CUSTOM_CAN_FALL,                 GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_FALL],
     NULL, NULL,
-    "can fall",                                "element can fall down"
+    "Can fall",                                        "Element can fall down"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
+    ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_CUSTOM_CAN_SMASH,                        GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_SMASH],
     NULL, " ",
-    NULL,                              "element can smash other elements"
+    NULL,                                      "Element can smash other elements"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
-    GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_SLIPPERY,                 GADGET_ID_NONE,
     &custom_element_properties[EP_SLIPPERY],
     NULL, NULL,
-    NULL,                              "other elements can fall down from it"
+    NULL,                                      "Other elements can fall down from it"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
-    GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_DEADLY,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_DEADLY,                   GADGET_ID_NONE,
     &custom_element_properties[EP_DEADLY],
     NULL, NULL,
-    NULL,                              "element can kill the player"
+    NULL,                                      "Element can kill the player"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
-    GADGET_ID_CUSTOM_CAN_EXPLODE,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_CUSTOM_CAN_EXPLODE,              GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_EXPLODE],
     NULL, NULL,
-    NULL,                              "element can explode"
+    NULL,                                      "Element can explode"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(12),
-    GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(12),
+    GADGET_ID_CUSTOM_EXPLODE_FIRE,             GADGET_ID_NONE,
     &custom_element_properties[EP_EXPLODES_BY_FIRE],
     NULL, NULL,
-    "by fire",                         "element can explode by fire/explosion"
+    "By fire",                                 "Element can explode by fire/explosion"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
-    GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
+    ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(12),
+    GADGET_ID_CUSTOM_EXPLODE_SMASH,            GADGET_ID_CUSTOM_EXPLODE_FIRE,
     &custom_element_properties[EP_EXPLODES_SMASHED],
     NULL, " ",
-    "smashed",                         "element can explode when smashed"
+    "Smashed",                                 "Element can explode when smashed"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
-    GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
+    ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT,
+    -1,                                                ED_ELEMENT_SETTINGS_YPOS(12),
+    GADGET_ID_CUSTOM_EXPLODE_IMPACT,           GADGET_ID_CUSTOM_EXPLODE_SMASH,
     &custom_element_properties[EP_EXPLODES_IMPACT],
     NULL, " ",
-    "impact",                          "element can explode on impact"
+    "Impact",                                  "Element can explode on impact"
   },
 
   // ---------- element settings: advanced (custom elements) ------------------
 
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_CUSTOM_CAN_CHANGE,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_CAN_CHANGE,               GADGET_ID_NONE,
     &custom_element_change.can_change,
     NULL, NULL,
-    "element changes to:",             "change element on specified condition"
+    "Element changes to:",                     "Change element on specified condition"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(2),
-    GADGET_ID_CHANGE_DELAY,            GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_DELAY,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_CHANGE_DELAY,                    GADGET_ID_NONE,
     &custom_element_change_events[CE_DELAY],
     NULL, NULL,
-    NULL,                              "element changes after delay"
+    NULL,                                      "Element changes after delay"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_CHANGE_BY_DIRECT_ACT,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_CHANGE_BY_DIRECT_ACT,            GADGET_ID_NONE,
     &custom_element_change_events[CE_BY_DIRECT_ACTION],
     NULL, NULL,
-    NULL,                              "element changes by direct action"
+    NULL,                                      "Element changes by direct action"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(5),
-    GADGET_ID_CHANGE_BY_OTHER_ACT,     GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_CHANGE_BY_OTHER_ACT,             GADGET_ID_NONE,
     &custom_element_change_events[CE_BY_OTHER_ACTION],
     NULL, NULL,
-    NULL,                              "element changes by other element"
+    NULL,                                      "Element changes by other element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(8),
-    GADGET_ID_CHANGE_USE_EXPLOSION,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_CHANGE_USE_EXPLOSION,            GADGET_ID_NONE,
     &custom_element_change.explode,
     NULL, NULL,
-    "explode instead of change",       "element explodes instead of change"
+    "Explode instead of change",               "Element explodes instead of change"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
-    GADGET_ID_CHANGE_USE_CONTENT,      GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT,
+    ED_ELEMENT_SETTINGS_XPOS(1),               ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_CHANGE_USE_CONTENT,              GADGET_ID_NONE,
     &custom_element_change.use_target_content,
     NULL, NULL,
-    "use extended change target:",     "element changes to more elements"
+    "Use extended change target:",             "Element changes to more elements"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(11),
-    GADGET_ID_CHANGE_ONLY_COMPLETE,    GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_CHANGE_ONLY_COMPLETE,            GADGET_ID_NONE,
     &custom_element_change.only_if_complete,
     NULL, NULL,
-    "replace all or nothing",          "only replace when all can be changed"
+    "Replace all or nothing",                  "Only replace when all can be changed"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(12),
-    GADGET_ID_CHANGE_USE_RANDOM,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM,
+    ED_ELEMENT_SETTINGS_XPOS(2),               ED_ELEMENT_SETTINGS_YPOS(12),
+    GADGET_ID_CHANGE_USE_RANDOM,               GADGET_ID_NONE,
     &custom_element_change.use_random_replace,
     NULL, NULL,
-    NULL,                              "use percentage for random replace"
+    NULL,                                      "Use percentage for random replace"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(13),
-    GADGET_ID_CHANGE_HAS_ACTION,       GADGET_ID_NONE,
+    ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_CHANGE_HAS_ACTION,               GADGET_ID_NONE,
     &custom_element_change.has_action,
     NULL, NULL,
-    NULL,                              "execute action on specified condition"
+    NULL,                                      "Execute action on specified condition"
   },
 };
 
 static struct
 {
+  int gadget_type_id;
   int x, y;
   int xoffset, yoffset;
   int gadget_id;
@@ -3547,293 +4648,677 @@ static struct
   // ---------- level playfield content ---------------------------------------
 
   {
-    0,                                 0,
-    0,                                 0,
-    GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
+    ED_DRAWING_ID_DRAWING_LEVEL,
+    0,                                         0,
+    0,                                         0,
+    GADGET_ID_DRAWING_LEVEL,                   GADGET_ID_NONE,
     NULL,
     -1, -1,    // these values are not constant, but can change at runtime
-    NULL, NULL, NULL, NULL,            NULL
+    NULL, NULL, NULL, NULL,                    NULL
   },
 
   // ---------- yam yam content -----------------------------------------------
 
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(0),    ED_AREA_YAMYAM_CONTENT_YOFF(0),
-    GADGET_ID_YAMYAM_CONTENT_0,                GADGET_ID_NONE,
-    &level.yamyam_content[0].e[0][0],  3, 3,
-    NULL, NULL, NULL, "1",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_0,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(0),            ED_AREA_YAMYAM_CONTENT_YOFF(0),
+    GADGET_ID_YAMYAM_CONTENT_0,                        GADGET_ID_NONE,
+    &level.yamyam_content[0].e[0][0],          3, 3,
+    NULL, NULL, NULL, "1",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(1),    ED_AREA_YAMYAM_CONTENT_YOFF(1),
-    GADGET_ID_YAMYAM_CONTENT_1,                GADGET_ID_NONE,
-    &level.yamyam_content[1].e[0][0],  3, 3,
-    NULL, NULL, NULL, "2",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_1,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(1),            ED_AREA_YAMYAM_CONTENT_YOFF(1),
+    GADGET_ID_YAMYAM_CONTENT_1,                        GADGET_ID_NONE,
+    &level.yamyam_content[1].e[0][0],          3, 3,
+    NULL, NULL, NULL, "2",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(2),    ED_AREA_YAMYAM_CONTENT_YOFF(2),
-    GADGET_ID_YAMYAM_CONTENT_2,                GADGET_ID_NONE,
-    &level.yamyam_content[2].e[0][0],  3, 3,
-    NULL, NULL, NULL, "3",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_2,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(2),            ED_AREA_YAMYAM_CONTENT_YOFF(2),
+    GADGET_ID_YAMYAM_CONTENT_2,                        GADGET_ID_NONE,
+    &level.yamyam_content[2].e[0][0],          3, 3,
+    NULL, NULL, NULL, "3",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(3),    ED_AREA_YAMYAM_CONTENT_YOFF(3),
-    GADGET_ID_YAMYAM_CONTENT_3,                GADGET_ID_NONE,
-    &level.yamyam_content[3].e[0][0],  3, 3,
-    NULL, NULL, NULL, "4",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_3,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(3),            ED_AREA_YAMYAM_CONTENT_YOFF(3),
+    GADGET_ID_YAMYAM_CONTENT_3,                        GADGET_ID_NONE,
+    &level.yamyam_content[3].e[0][0],          3, 3,
+    NULL, NULL, NULL, "4",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(4),    ED_AREA_YAMYAM_CONTENT_YOFF(4),
-    GADGET_ID_YAMYAM_CONTENT_4,                GADGET_ID_NONE,
-    &level.yamyam_content[4].e[0][0],  3, 3,
-    NULL, NULL, NULL, "5",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_4,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(4),            ED_AREA_YAMYAM_CONTENT_YOFF(4),
+    GADGET_ID_YAMYAM_CONTENT_4,                        GADGET_ID_NONE,
+    &level.yamyam_content[4].e[0][0],          3, 3,
+    NULL, NULL, NULL, "5",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(5),    ED_AREA_YAMYAM_CONTENT_YOFF(5),
-    GADGET_ID_YAMYAM_CONTENT_5,                GADGET_ID_NONE,
-    &level.yamyam_content[5].e[0][0],  3, 3,
-    NULL, NULL, NULL, "6",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_5,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(5),            ED_AREA_YAMYAM_CONTENT_YOFF(5),
+    GADGET_ID_YAMYAM_CONTENT_5,                        GADGET_ID_NONE,
+    &level.yamyam_content[5].e[0][0],          3, 3,
+    NULL, NULL, NULL, "6",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(6),    ED_AREA_YAMYAM_CONTENT_YOFF(6),
-    GADGET_ID_YAMYAM_CONTENT_6,                GADGET_ID_NONE,
-    &level.yamyam_content[6].e[0][0],  3, 3,
-    NULL, NULL, NULL, "7",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_6,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(6),            ED_AREA_YAMYAM_CONTENT_YOFF(6),
+    GADGET_ID_YAMYAM_CONTENT_6,                        GADGET_ID_NONE,
+    &level.yamyam_content[6].e[0][0],          3, 3,
+    NULL, NULL, NULL, "7",                     NULL
   },
   {
-    ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
-    ED_AREA_YAMYAM_CONTENT_XOFF(7),    ED_AREA_YAMYAM_CONTENT_YOFF(7),
-    GADGET_ID_YAMYAM_CONTENT_7,                GADGET_ID_NONE,
-    &level.yamyam_content[7].e[0][0],  3, 3,
-    NULL, NULL, NULL, "8",             NULL
+    ED_DRAWING_ID_YAMYAM_CONTENT_7,
+    ED_AREA_YAMYAM_CONTENT_XPOS,               ED_AREA_YAMYAM_CONTENT_YPOS,
+    ED_AREA_YAMYAM_CONTENT_XOFF(7),            ED_AREA_YAMYAM_CONTENT_YOFF(7),
+    GADGET_ID_YAMYAM_CONTENT_7,                        GADGET_ID_NONE,
+    &level.yamyam_content[7].e[0][0],          3, 3,
+    NULL, NULL, NULL, "8",                     NULL
   },
 
   // ---------- magic ball content --------------------------------------------
 
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
-    GADGET_ID_MAGIC_BALL_CONTENT_0,    GADGET_ID_NONE,
-    &level.ball_content[0].e[0][0],    3, 3,
-    NULL, NULL, NULL, "1",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_0,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
+    GADGET_ID_MAGIC_BALL_CONTENT_0,            GADGET_ID_NONE,
+    &level.ball_content[0].e[0][0],            3, 3,
+    NULL, NULL, NULL, "1",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
-    GADGET_ID_MAGIC_BALL_CONTENT_1,    GADGET_ID_NONE,
-    &level.ball_content[1].e[0][0],    3, 3,
-    NULL, NULL, NULL, "2",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_1,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
+    GADGET_ID_MAGIC_BALL_CONTENT_1,            GADGET_ID_NONE,
+    &level.ball_content[1].e[0][0],            3, 3,
+    NULL, NULL, NULL, "2",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
-    GADGET_ID_MAGIC_BALL_CONTENT_2,    GADGET_ID_NONE,
-    &level.ball_content[2].e[0][0],    3, 3,
-    NULL, NULL, NULL, "3",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_2,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
+    GADGET_ID_MAGIC_BALL_CONTENT_2,            GADGET_ID_NONE,
+    &level.ball_content[2].e[0][0],            3, 3,
+    NULL, NULL, NULL, "3",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
-    GADGET_ID_MAGIC_BALL_CONTENT_3,    GADGET_ID_NONE,
-    &level.ball_content[3].e[0][0],    3, 3,
-    NULL, NULL, NULL, "4",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_3,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
+    GADGET_ID_MAGIC_BALL_CONTENT_3,            GADGET_ID_NONE,
+    &level.ball_content[3].e[0][0],            3, 3,
+    NULL, NULL, NULL, "4",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
-    GADGET_ID_MAGIC_BALL_CONTENT_4,    GADGET_ID_NONE,
-    &level.ball_content[4].e[0][0],    3, 3,
-    NULL, NULL, NULL, "5",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_4,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
+    GADGET_ID_MAGIC_BALL_CONTENT_4,            GADGET_ID_NONE,
+    &level.ball_content[4].e[0][0],            3, 3,
+    NULL, NULL, NULL, "5",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
-    GADGET_ID_MAGIC_BALL_CONTENT_5,    GADGET_ID_NONE,
-    &level.ball_content[5].e[0][0],    3, 3,
-    NULL, NULL, NULL, "6",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_5,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
+    GADGET_ID_MAGIC_BALL_CONTENT_5,            GADGET_ID_NONE,
+    &level.ball_content[5].e[0][0],            3, 3,
+    NULL, NULL, NULL, "6",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
-    GADGET_ID_MAGIC_BALL_CONTENT_6,    GADGET_ID_NONE,
-    &level.ball_content[6].e[0][0],    3, 3,
-    NULL, NULL, NULL, "7",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_6,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
+    GADGET_ID_MAGIC_BALL_CONTENT_6,            GADGET_ID_NONE,
+    &level.ball_content[6].e[0][0],            3, 3,
+    NULL, NULL, NULL, "7",                     NULL
   },
   {
-    ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
-    ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
-    GADGET_ID_MAGIC_BALL_CONTENT_7,    GADGET_ID_NONE,
-    &level.ball_content[7].e[0][0],    3, 3,
-    NULL, NULL, NULL, "8",             NULL
+    ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
+    ED_AREA_MAGIC_BALL_CONTENT_XPOS,           ED_AREA_MAGIC_BALL_CONTENT_YPOS,
+    ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),                ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
+    GADGET_ID_MAGIC_BALL_CONTENT_7,            GADGET_ID_NONE,
+    &level.ball_content[7].e[0][0],            3, 3,
+    NULL, NULL, NULL, "8",                     NULL
   },
 
   // ---------- android content -----------------------------------------------
 
   {
-    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(6),
-    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_ANDROID_CONTENT,         GADGET_ID_NONE,
-    &level.android_clone_element[0],   MAX_ANDROID_ELEMENTS, 1,
-    NULL, NULL, "elements:", NULL,     "elements android can clone"
+    ED_DRAWING_ID_ANDROID_CONTENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_ANDROID_CONTENT,                 GADGET_ID_NONE,
+    &level.android_clone_element[0],           MAX_ANDROID_ELEMENTS, 1,
+    NULL, NULL, "Elements:", NULL,             "Elements android can clone"
   },
 
   // ---------- amoeba content ------------------------------------------------
 
   {
-    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(3),
-    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_AMOEBA_CONTENT,          GADGET_ID_NONE,
-    &level.amoeba_content,             1, 1,
-    "content:", NULL, NULL, NULL,      "amoeba content"
+    ED_DRAWING_ID_AMOEBA_CONTENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(3),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_AMOEBA_CONTENT,                  GADGET_ID_NONE,
+    &level.amoeba_content,                     1, 1,
+    "Content:", NULL, NULL, NULL,              "Amoeba content"
   },
 
-  // ---------- level start element -------------------------------------------
+  // ---------- BD snap element -----------------------------------------------
 
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(10),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_START_ELEMENT,           GADGET_ID_USE_START_ELEMENT,
-    &level.start_element[0],           1, 1,
-    NULL, NULL, NULL, NULL,            "level start element"
+    ED_DRAWING_ID_BD_SNAP_ELEMENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SNAP_ELEMENT,                 GADGET_ID_NONE,
+    &level.bd_snap_element,                    1, 1,
+    "Snap element:", NULL, NULL, NULL,         "Element created when snapping"
   },
 
-  // ---------- player artwork element ----------------------------------------
+  // ---------- BD magic wall elements ----------------------------------------
 
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(11),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_ARTWORK_ELEMENT,         GADGET_ID_USE_ARTWORK_ELEMENT,
-    &level.artwork_element[0],         1, 1,
-    NULL, NULL, NULL, NULL,            "element for player artwork"
+    ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,                GADGET_ID_NONE,
+    &level.bd_magic_wall_diamond_to,           1, 1,
+    "Changes diamonds to:", NULL, NULL, NULL,  "Element to turn diamonds to"
   },
-
-  // ---------- player explosion element --------------------------------------
-
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(12),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_EXPLOSION_ELEMENT,       GADGET_ID_USE_EXPLOSION_ELEMENT,
-    &level.explosion_element[0],       1, 1,
-    NULL, NULL, NULL, NULL,            "element for player explosion"
+    ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_ROCK_TO,           GADGET_ID_NONE,
+    &level.bd_magic_wall_rock_to,              1, 1,
+    "Changes rocks to:", NULL, NULL, NULL,     "Element to turn rocks to"
   },
-
-  // ---------- player initial inventory --------------------------------------
-
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_INVENTORY_CONTENT,       GADGET_ID_USE_INITIAL_INVENTORY,
-    &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
-    NULL, NULL, NULL, NULL,            "content for initial inventory"
+    ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(8),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,      GADGET_ID_NONE,
+    &level.bd_magic_wall_mega_rock_to,         1, 1,
+    "Changes mega rocks to:", NULL, NULL, NULL,        "Element to turn mega rocks to"
   },
-
-  // ---------- element settings: configure 1 (custom elements) ---------------
-
-  // ---------- custom graphic ------------------------------------------------
-
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
-    &custom_element.gfx_element_initial,1, 1,
-    NULL, NULL, NULL, NULL,            "custom graphic element"
+    ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(9),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_NUT_TO,            GADGET_ID_NONE,
+    &level.bd_magic_wall_nut_to,               1, 1,
+    "Changes nuts to:", NULL, NULL, NULL,      "Element to turn nuts to"
   },
-
-  // ---------- element settings: configure 2 (custom elements) ---------------
-
-  // ---------- custom content (when exploding) -------------------------------
-
   {
-    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(11),
-    0,                                 ED_AREA_3X3_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, // align three rows
-    &custom_element.content.e[0][0],   3, 3,
-    "content:", NULL, NULL, NULL,      NULL
+    ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(10),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,     GADGET_ID_NONE,
+    &level.bd_magic_wall_nitro_pack_to,                1, 1,
+    "Changes nitro packs to:", NULL, NULL, NULL, "Element to turn nitro packs to"
   },
-
-  // ---------- custom enter and leave element (when moving) ------------------
-
   {
-    ED_AREA_1X1_SETTINGS_XPOS(1),      ED_AREA_1X1_SETTINGS_YPOS(3),
-    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_MOVE_ENTER,       GADGET_ID_NONE,
-    &custom_element.move_enter_element,        1, 1,
-    "can dig:", " ", NULL, NULL,       "element that can be digged/collected"
+    ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(11),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO, GADGET_ID_NONE,
+    &level.bd_magic_wall_flying_diamond_to,    1, 1,
+    "Changes flying diamonds to:", NULL, NULL, NULL, "Element to turn flying diamonds to"
   },
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(3),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_MOVE_LEAVE,       GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
-    &custom_element.move_leave_element,        1, 1,
-    NULL, NULL, NULL, NULL,            "element that will be left behind"
+    ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(12),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,    GADGET_ID_NONE,
+    &level.bd_magic_wall_flying_rock_to,       1, 1,
+    "Changes flying rocks to:", NULL, NULL, NULL, "Element to turn flying rocks to"
   },
 
-  // ---------- element settings: advanced (custom elements) ------------------
-
-  // ---------- custom change target ------------------------------------------
+  // ---------- BD amoeba 1 content -------------------------------------------
 
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_CHANGE_TARGET,    GADGET_ID_CUSTOM_CAN_CHANGE,
-    &custom_element_change.target_element, 1, 1,
-    NULL, "after/when:", NULL, NULL,   "new target element after change"
+    ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_TOO_BIG,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_1_CONTENT_TOO_BIG,     GADGET_ID_NONE,
+    &level.bd_amoeba_1_content_too_big,                1, 1,
+    "If too big, changes to:", NULL, NULL, NULL, "Amoeba 1 content if too big"
   },
-
-  // ---------- custom change content (extended change target) ----------------
-
   {
-    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(9),
-    0,                                 ED_AREA_3X3_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_CHANGE_CONTENT,   GADGET_ID_NONE, // align three rows
-    &custom_element_change.target_content.e[0][0], 3, 3,
-    NULL, NULL, NULL, NULL,            "new extended elements after change"
+    ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_ENCLOSED,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(8),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_1_CONTENT_ENCLOSED,    GADGET_ID_NONE,
+    &level.bd_amoeba_1_content_enclosed,       1, 1,
+    "If enclosed, changes to:", NULL, NULL, NULL, "Amoeba 1 content if enclosed"
   },
 
-  // ---------- custom change trigger (element causing change) ----------------
+  // ---------- BD amoeba 2 content -------------------------------------------
 
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(5),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_CHANGE_TRIGGER,   GADGET_ID_CHANGE_OTHER_ACTION,
-    &custom_element_change.initial_trigger_element, 1, 1,
-    NULL, NULL, NULL, NULL,            "other element triggering change"
+    ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,     GADGET_ID_NONE,
+    &level.bd_amoeba_2_content_too_big,                1, 1,
+    "If too big, changes to:", NULL, NULL, NULL, "Amoeba 2 content if too big"
+  },
+  {
+    ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(8),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_2_CONTENT_ENCLOSED,    GADGET_ID_NONE,
+    &level.bd_amoeba_2_content_enclosed,       1, 1,
+    "If enclosed, changes to:", NULL, NULL, NULL, "Amoeba 2 content if enclosed"
+  },
+  {
+    ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(10),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_2_CONTENT_EXPLODING,   GADGET_ID_NONE,
+    &level.bd_amoeba_2_content_exploding,      1, 1,
+    "If exploding, changes to:", NULL, NULL, NULL, "Amoeba 2 content if exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(11),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE,  GADGET_ID_NONE,
+    &level.bd_amoeba_2_content_looks_like,     1, 1,
+    "Use graphic of element:", NULL, NULL, NULL, "Amoeba 2 looks like this element"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_EATS_ELEMENT_1,         GADGET_ID_NONE,
+    &level.bd_slime_eats_element_1,            1, 1,
+    "Can eat:", NULL, NULL, NULL,              "Element that can be eaten"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1,  GADGET_ID_BD_SLIME_EATS_ELEMENT_1,
+    &level.bd_slime_converts_to_element_1,     1, 1,
+    " and convert to:", NULL, NULL, NULL,      "Eaten element is converted to"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_EATS_ELEMENT_2,         GADGET_ID_NONE,
+    &level.bd_slime_eats_element_2,            1, 1,
+    "Can eat:", NULL, NULL, NULL,              "Element that can be eaten"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2,  GADGET_ID_BD_SLIME_EATS_ELEMENT_2,
+    &level.bd_slime_converts_to_element_2,     1, 1,
+    " and convert to:", NULL, NULL, NULL,      "Eaten element is converted to"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_EATS_ELEMENT_3,         GADGET_ID_NONE,
+    &level.bd_slime_eats_element_3,            1, 1,
+    "Can eat:", NULL, NULL, NULL,              "Element that can be eaten"
+  },
+  {
+    ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3,  GADGET_ID_BD_SLIME_EATS_ELEMENT_3,
+    &level.bd_slime_converts_to_element_3,     1, 1,
+    " and convert to:", NULL, NULL, NULL,      "Eaten element is converted to"
+  },
+  {
+    ED_DRAWING_ID_BD_ACID_EATS_ELEMENT,
+    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_ACID_EATS_ELEMENT,            GADGET_ID_NONE,
+    &level.bd_acid_eats_element,               1, 1,
+    "Can eat:", NULL, NULL, NULL,              "Eats this element when spreading"
+  },
+  {
+    ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(3),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_ACID_TURNS_TO_ELEMENT,                GADGET_ID_NONE,
+    &level.bd_acid_turns_to_element,           1, 1,
+    "Can leave behind:", NULL, NULL, NULL,     "Turns to this element after spreading"
+  },
+  {
+    ED_DRAWING_ID_BD_BITER_EATS_ELEMENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_BITER_EATS_ELEMENT,           GADGET_ID_NONE,
+    &level.bd_biter_eats_element,              1, 1,
+    "Can eat:", NULL, NULL, NULL,              "Eats this element when moving"
+  },
+  {
+    ED_DRAWING_ID_BD_BLADDER_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,
+    GADGET_ID_BD_BLADDER_CONVERTS_BY_ELEMENT,  GADGET_ID_NONE,
+    &level.bd_bladder_converts_by_element,     1, 1,
+    "Turns to clock by touching:", NULL, NULL, NULL, "Turns to clock by touching element"
+  },
+  {
+    ED_DRAWING_ID_BD_NUT_CONTENT,
+    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_NUT_CONTENT,                  GADGET_ID_NONE,
+    &level.bd_nut_content,                     1, 1,
+    "When breaking, changes to:", NULL, NULL, NULL, "Element created when breaking nut"
+  },
+  {
+    ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE,
+    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_EXPANDING_WALL_LOOKS_LIKE,    GADGET_ID_NONE,
+    &level.bd_expanding_wall_looks_like,       1, 1,
+    "Use graphic of element:", NULL, NULL, NULL, "Expanding wall looks like this element"
+  },
+  {
+    ED_DRAWING_ID_BD_SAND_LOOKS_LIKE,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SAND_LOOKS_LIKE,              GADGET_ID_NONE,
+    &level.bd_sand_looks_like,                 1, 1,
+    "Use graphic of element:", NULL, NULL, NULL, "Sand looks like this element"
+  },
+  {
+    ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_ROCK_TURNS_TO_ON_FALLING,     GADGET_ID_NONE,
+    &level.bd_rock_turns_to_on_falling,                1, 1,
+    "Turns to when falling:", NULL, NULL, NULL,        "Changes to this when falling starts"
+  },
+  {
+    ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(3),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_ROCK_TURNS_TO_ON_IMPACT,      GADGET_ID_NONE,
+    &level.bd_rock_turns_to_on_impact,         1, 1,
+    "Turns to on impact:", NULL, NULL, NULL,   "Changes to this when falling stops"
+  },
+  {
+    ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_DIAMOND_TURNS_TO_ON_FALLING,  GADGET_ID_NONE,
+    &level.bd_diamond_turns_to_on_falling,     1, 1,
+    "Turns to when falling:", NULL, NULL, NULL,        "Changes to this when falling starts"
+  },
+  {
+    ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(3),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT,   GADGET_ID_NONE,
+    &level.bd_diamond_turns_to_on_impact,      1, 1,
+    "Turns to on impact:", NULL, NULL, NULL,   "Changes to this when falling stops"
+  },
+  {
+    ED_DRAWING_ID_BD_FIREFLY_1_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_FIREFLY_1_EXPLODES_TO,                GADGET_ID_NONE,
+    &level.bd_firefly_1_explodes_to,           1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_FIREFLY_2_EXPLODES_TO,                GADGET_ID_NONE,
+    &level.bd_firefly_2_explodes_to,           1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_BUTTERFLY_1_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_BUTTERFLY_1_EXPLODES_TO,      GADGET_ID_NONE,
+    &level.bd_butterfly_1_explodes_to,         1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_BUTTERFLY_2_EXPLODES_TO,      GADGET_ID_NONE,
+    &level.bd_butterfly_2_explodes_to,         1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_STONEFLY_EXPLODES_TO,         GADGET_ID_NONE,
+    &level.bd_stonefly_explodes_to,            1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_DRAGONFLY_EXPLODES_TO,                GADGET_ID_NONE,
+    &level.bd_dragonfly_explodes_to,           1, 1,
+    "Explodes to:", NULL, NULL, NULL,          "Changes to this when exploding"
+  },
+  {
+    ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO,
+    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_DIAMOND_BIRTH_TURNS_TO,       GADGET_ID_NONE,
+    &level.bd_diamond_birth_turns_to,          1, 1,
+    "Explosion ends in:", NULL, NULL, NULL,    "Changes to this after explosion"
+  },
+  {
+    ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_BOMB_EXPLOSION_TURNS_TO,      GADGET_ID_NONE,
+    &level.bd_bomb_explosion_turns_to,         1, 1,
+    "Explosion ends in:", NULL, NULL, NULL,    "Changes to this after explosion"
+  },
+  {
+    ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(0),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_NITRO_EXPLOSION_TURNS_TO,     GADGET_ID_NONE,
+    &level.bd_nitro_explosion_turns_to,                1, 1,
+    "Explosion ends in:", NULL, NULL, NULL,    "Changes to this after explosion"
+  },
+  {
+    ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO,
+    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_EXPLOSION_TURNS_TO,           GADGET_ID_NONE,
+    &level.bd_explosion_turns_to,              1, 1,
+    "Explosion ends in:", NULL, NULL, NULL,    "Changes to this after explosion"
+  },
+
+  // ---------- level start element -------------------------------------------
+
+  {
+    ED_DRAWING_ID_START_ELEMENT,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(10),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_START_ELEMENT,                   GADGET_ID_USE_START_ELEMENT,
+    &level.start_element[0],                   1, 1,
+    NULL, NULL, NULL, NULL,                    "Level start element"
+  },
+
+  // ---------- player artwork element ----------------------------------------
+
+  {
+    ED_DRAWING_ID_ARTWORK_ELEMENT,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(11),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_ARTWORK_ELEMENT,                 GADGET_ID_USE_ARTWORK_ELEMENT,
+    &level.artwork_element[0],                 1, 1,
+    NULL, NULL, NULL, NULL,                    "Element for player artwork"
+  },
+
+  // ---------- player explosion element --------------------------------------
+
+  {
+    ED_DRAWING_ID_EXPLOSION_ELEMENT,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(12),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_EXPLOSION_ELEMENT,               GADGET_ID_USE_EXPLOSION_ELEMENT,
+    &level.explosion_element[0],               1, 1,
+    NULL, NULL, NULL, NULL,                    "Element for player explosion"
+  },
+
+  // ---------- player initial inventory --------------------------------------
+
+  {
+    ED_DRAWING_ID_INVENTORY_CONTENT,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(1),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_INVENTORY_CONTENT,               GADGET_ID_USE_INITIAL_INVENTORY,
+    &level.initial_inventory_content[0][0],    MAX_INITIAL_INVENTORY_SIZE, 1,
+    NULL, NULL, NULL, NULL,                    "Content for initial inventory"
+  },
+
+  // ---------- gray ball content -----------------------------------------
+
+  {
+    ED_DRAWING_ID_MM_BALL_CONTENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_MM_BALL_CONTENT,                 GADGET_ID_NONE,
+    &level.mm_ball_content[0],                 MAX_MM_BALL_CONTENTS, 1,
+    "Content:", NULL, NULL, NULL,              "Content for gray ball"
+  },
+
+  // ---------- element settings: configure 1 (custom elements) ---------------
+
+  // ---------- custom graphic ------------------------------------------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_GRAPHIC,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(1),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_GRAPHIC,                  GADGET_ID_CUSTOM_USE_GRAPHIC,
+    &custom_element.gfx_element_initial,       1, 1,
+    NULL, NULL, NULL, NULL,                    "Custom graphic element"
+  },
+
+  // ---------- element settings: configure 2 (custom elements) ---------------
+
+  // ---------- custom content (when exploding) -------------------------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_CONTENT,
+    -1,                                                ED_AREA_3X3_SETTINGS_YPOS(11),
+    0,                                         ED_AREA_3X3_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_CONTENT,                  GADGET_ID_NONE,         // align three rows
+    &custom_element.content.e[0][0],           3, 3,
+    "Content:", NULL, NULL, NULL,              NULL
+  },
+
+  // ---------- custom enter and leave element (when moving) ------------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
+    ED_AREA_1X1_SETTINGS_XPOS(1),              ED_AREA_1X1_SETTINGS_YPOS(3),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_MOVE_ENTER,               GADGET_ID_NONE,
+    &custom_element.move_enter_element,                1, 1,
+    "Can dig:", " ", NULL, NULL,               "Element that can be digged/collected"
+  },
+  {
+    ED_DRAWING_ID_CUSTOM_MOVE_LEAVE,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(3),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_MOVE_LEAVE,               GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
+    &custom_element.move_leave_element,                1, 1,
+    NULL, NULL, NULL, NULL,                    "Element that will be left behind"
+  },
+
+  // ---------- element settings: advanced (custom elements) ------------------
+
+  // ---------- custom change target ------------------------------------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_CHANGE_TARGET,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(1),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_CHANGE_TARGET,            GADGET_ID_CUSTOM_CAN_CHANGE,
+    &custom_element_change.target_element,     1, 1,
+    NULL, "after/when:", NULL, NULL,           "New target element after change"
+  },
+
+  // ---------- custom change content (extended change target) ----------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT,
+    -1,                                                ED_AREA_3X3_SETTINGS_YPOS(9),
+    0,                                         ED_AREA_3X3_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_CHANGE_CONTENT,           GADGET_ID_NONE,         // align three rows
+    &custom_element_change.target_content.e[0][0], 3, 3,
+    NULL, NULL, NULL, NULL,                    "New extended elements after change"
+  },
+
+  // ---------- custom change trigger (element causing change) ----------------
+
+  {
+    ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(5),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_CHANGE_TRIGGER,           GADGET_ID_CHANGE_OTHER_ACTION,
+    &custom_element_change.initial_trigger_element, 1, 1,
+    NULL, NULL, NULL, NULL,                    "Other element triggering change"
   },
 
   // ---------- custom change action (element used for action) ----------------
 
   {
-    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(13),
-    0,                                 ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_CUSTOM_CHANGE_ACTION,    GADGET_ID_ACTION_ARG,
-    &custom_element_change.action_element, 1, 1,
-    NULL, NULL, NULL, NULL,            "element used as action parameter"
+    ED_DRAWING_ID_CUSTOM_CHANGE_ACTION,
+    -1,                                                ED_AREA_1X1_SETTINGS_YPOS(13),
+    0,                                         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_CUSTOM_CHANGE_ACTION,            GADGET_ID_ACTION_ARG,
+    &custom_element_change.action_element,     1, 1,
+    NULL, NULL, NULL, NULL,                    "Element used as action parameter"
   },
 
   // ---------- group element content -----------------------------------------
 
   {
-    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(2),
-    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
-    GADGET_ID_GROUP_CONTENT,           GADGET_ID_NONE,
-    &group_element_info.element[0],    MAX_ELEMENTS_IN_GROUP, 1,
-    "content:", NULL, NULL, NULL,      NULL
+    ED_DRAWING_ID_GROUP_CONTENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_GROUP_CONTENT,                   GADGET_ID_NONE,
+    &group_element_info.element[0],            MAX_ELEMENTS_IN_GROUP, 1,
+    "Content:", NULL, NULL, NULL,              NULL
   },
 
   // ---------- random background (for random painting) -----------------------
 
   {
-    -1,                                        ED_AREA_1X1_LSETTINGS_YPOS(1),
-    0,                                 ED_AREA_1X1_LSETTINGS_YOFF,
-    GADGET_ID_RANDOM_BACKGROUND,       GADGET_ID_RANDOM_RESTRICTED,
-    &random_placement_background_element, 1, 1,
-    NULL, NULL, NULL, NULL,            "random placement background"
+    ED_DRAWING_ID_RANDOM_BACKGROUND,
+    -1,                                                ED_AREA_1X1_LSETTINGS_YPOS(1),
+    0,                                         ED_AREA_1X1_LSETTINGS_YOFF,
+    GADGET_ID_RANDOM_BACKGROUND,               GADGET_ID_RANDOM_RESTRICTED,
+    &random_placement_background_element,      1, 1,
+    NULL, NULL, NULL, NULL,                    "Random placement background"
   },
 };
 
@@ -3855,7 +5340,7 @@ static int level_xpos = -1, level_ypos = -1;
 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
 
-#define IN_ED_FIELD(x,y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
+#define IN_ED_FIELD(x, y)      IN_FIELD(x, y, ed_fieldx, ed_fieldy)
 
 // drawing elements on the three mouse buttons
 static int new_element1 = EL_WALL;
@@ -3889,7 +5374,7 @@ static void AdjustElementListScrollbar(void);
 static void RedrawDrawingElements(void);
 static void DrawDrawingWindowExt(boolean);
 static void DrawDrawingWindow(void);
-static void DrawLevelInfoWindow(void);
+static void DrawLevelConfigWindow(void);
 static void DrawPropertiesWindow(void);
 static void DrawPaletteWindow(void);
 static void UpdateCustomElementGraphicGadgets(void);
@@ -3914,6 +5399,7 @@ static boolean getDrawModeHiRes(void);
 static int getTabulatorBarWidth(void);
 static int getTabulatorBarHeight(void);
 static Pixel getTabulatorBarColor(void);
+static int numHiresTiles(int);
 
 static int num_editor_gadgets = 0;     // dynamically determined
 
@@ -3933,7 +5419,8 @@ static int undo_buffer_steps = 0;
 static int redo_buffer_steps = 0;
 
 static int edit_mode;
-static int edit_mode_levelinfo;
+static int edit_mode_levelconfig;
+static int edit_mode_engineconfig;
 static int edit_mode_properties;
 
 static int element_shift = 0;
@@ -3988,6 +5475,321 @@ static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
 static int num_editor_hl_boulderdash = ARRAY_SIZE(editor_hl_boulderdash);
 static int num_editor_el_boulderdash = ARRAY_SIZE(editor_el_boulderdash);
 
+static int editor_hl_boulderdash_native[] =
+{
+  EL_INTERNAL_CASCADE_BDX_ACTIVE,
+  EL_CHAR('B'),
+  EL_CHAR('D'),
+  EL_EMPTY,
+};
+
+static int editor_el_boulderdash_native[] =
+{
+  EL_EMPTY,
+  EL_BDX_SAND_1,
+  EL_BDX_ROCK,
+  EL_BDX_DIAMOND,
+
+  EL_BDX_INBOX,
+  EL_BDX_STEELWALL,
+  EL_BDX_WALL,
+  EL_BDX_MAGIC_WALL,
+
+  EL_BDX_AMOEBA_1,
+  EL_BDX_BUTTERFLY_1_UP,
+  EL_BDX_FIREFLY_1_UP,
+  EL_BDX_EXIT_CLOSED,
+
+  EL_BDX_BUTTERFLY_1_LEFT,
+  EL_BDX_FIREFLY_1_LEFT,
+  EL_BDX_BUTTERFLY_1_RIGHT,
+  EL_BDX_FIREFLY_1_RIGHT,
+
+  EL_BDX_SAND_2,
+  EL_BDX_BUTTERFLY_1_DOWN,
+  EL_BDX_FIREFLY_1_DOWN,
+  EL_BDX_EXIT_OPEN,
+
+  EL_BDX_AMOEBA_2,
+  EL_BDX_BUTTERFLY_2_UP,
+  EL_BDX_FIREFLY_2_UP,
+  EL_BDX_SLIME,
+
+  EL_BDX_BUTTERFLY_2_LEFT,
+  EL_BDX_FIREFLY_2_LEFT,
+  EL_BDX_BUTTERFLY_2_RIGHT,
+  EL_BDX_FIREFLY_2_RIGHT,
+
+  EL_BDX_BOMB,
+  EL_BDX_BUTTERFLY_2_DOWN,
+  EL_BDX_FIREFLY_2_DOWN,
+  EL_BDX_FLYING_DIAMOND,
+
+  EL_BDX_NITRO_PACK,
+  EL_BDX_DRAGONFLY_UP,
+  EL_BDX_STONEFLY_UP,
+  EL_BDX_DIAMOND_GLUED,
+
+  EL_BDX_DRAGONFLY_LEFT,
+  EL_BDX_STONEFLY_LEFT,
+  EL_BDX_DRAGONFLY_RIGHT,
+  EL_BDX_STONEFLY_RIGHT,
+
+  EL_BDX_NUT,
+  EL_BDX_DRAGONFLY_DOWN,
+  EL_BDX_STONEFLY_DOWN,
+  EL_EMPTY,
+
+  EL_BDX_BITER_SWITCH_1,
+  EL_BDX_BITER_UP,
+  EL_BDX_COW_UP,
+  EL_EMPTY,
+
+  EL_BDX_BITER_LEFT,
+  EL_BDX_COW_LEFT,
+  EL_BDX_BITER_RIGHT,
+  EL_BDX_COW_RIGHT,
+
+  EL_BDX_VOODOO_DOLL,
+  EL_BDX_BITER_DOWN,
+  EL_BDX_COW_DOWN,
+  EL_BDX_GHOST,
+
+  EL_BDX_SAND_GLUED,
+  EL_BDX_SAND_BALL,
+  EL_BDX_SAND_LOOSE,
+  EL_BDX_WALL_NON_SLOPED,
+
+  EL_BDX_SAND_SLOPED_UP_LEFT,
+  EL_BDX_SAND_SLOPED_UP_RIGHT,
+  EL_BDX_WALL_SLOPED_UP_LEFT,
+  EL_BDX_WALL_SLOPED_UP_RIGHT,
+
+  EL_BDX_SAND_SLOPED_DOWN_LEFT,
+  EL_BDX_SAND_SLOPED_DOWN_RIGHT,
+  EL_BDX_WALL_SLOPED_DOWN_LEFT,
+  EL_BDX_WALL_SLOPED_DOWN_RIGHT,
+
+  EL_BDX_FLYING_ROCK,
+  EL_BDX_ROCK_GLUED,
+  EL_BDX_STEELWALL_SLOPED_UP_LEFT,
+  EL_BDX_STEELWALL_SLOPED_UP_RIGHT,
+
+  EL_BDX_WAITING_ROCK,
+  EL_BDX_CHASING_ROCK,
+  EL_BDX_STEELWALL_SLOPED_DOWN_LEFT,
+  EL_BDX_STEELWALL_SLOPED_DOWN_RIGHT,
+
+  EL_BDX_MEGA_ROCK,
+  EL_BDX_SWEET,
+  EL_BDX_INVISIBLE_EXIT_CLOSED,
+  EL_BDX_INVISIBLE_EXIT_OPEN,
+
+  EL_BDX_STEELWALL_EXPLODABLE,
+  EL_BDX_STEELWALL_DIGGABLE,
+  EL_BDX_WALL_DIGGABLE,
+  EL_BDX_FALLING_WALL,
+
+  EL_BDX_EXPANDABLE_WALL_HORIZONTAL,
+  EL_BDX_EXPANDABLE_WALL_VERTICAL,
+  EL_BDX_EXPANDABLE_WALL_ANY,
+  EL_BDX_EXPANDABLE_WALL_SWITCH,
+
+  EL_BDX_EXPANDABLE_STEELWALL_HORIZONTAL,
+  EL_BDX_EXPANDABLE_STEELWALL_VERTICAL,
+  EL_BDX_EXPANDABLE_STEELWALL_ANY,
+  EL_BDX_CREATURE_SWITCH,
+
+  EL_BDX_BLADDER,
+  EL_BDX_BLADDER_SPENDER,
+  EL_BDX_REPLICATOR,
+  EL_BDX_REPLICATOR_SWITCH,
+
+  EL_BDX_CONVEYOR_LEFT,
+  EL_BDX_CONVEYOR_RIGHT,
+  EL_BDX_CONVEYOR_SWITCH,
+  EL_BDX_CONVEYOR_DIR_SWITCH,
+
+  EL_BDX_CLOCK,
+  EL_BDX_TIME_PENALTY,
+  EL_BDX_GRAVESTONE,
+  EL_BDX_SKELETON,
+
+  EL_BDX_WATER,
+  EL_BDX_ACID,
+  EL_BDX_LAVA,
+  EL_BDX_BOX,
+
+  EL_BDX_GATE_1,
+  EL_BDX_GATE_2,
+  EL_BDX_GATE_3,
+  EL_BDX_TRAPPED_DIAMOND,
+
+  EL_BDX_KEY_1,
+  EL_BDX_KEY_2,
+  EL_BDX_KEY_3,
+  EL_BDX_DIAMOND_KEY,
+
+  EL_BDX_WALL_KEY_1,
+  EL_BDX_WALL_KEY_2,
+  EL_BDX_WALL_KEY_3,
+  EL_BDX_WALL_DIAMOND,
+
+  EL_BDX_POT,
+  EL_BDX_GRAVITY_SWITCH,
+  EL_BDX_PNEUMATIC_HAMMER,
+  EL_BDX_TELEPORTER,
+
+  EL_BDX_PLAYER,
+  EL_BDX_PLAYER_WITH_BOMB,
+  EL_BDX_PLAYER_WITH_ROCKET_LAUNCHER,
+  EL_BDX_ROCKET_LAUNCHER,
+
+  EL_BDX_PLAYER_GLUED,
+  EL_BDX_PLAYER_STIRRING,
+  EL_EMPTY,
+  EL_EMPTY,
+};
+static int *editor_hl_boulderdash_native_ptr = editor_hl_boulderdash_native;
+static int *editor_el_boulderdash_native_ptr = editor_el_boulderdash_native;
+static int num_editor_hl_boulderdash_native = ARRAY_SIZE(editor_hl_boulderdash_native);
+static int num_editor_el_boulderdash_native = ARRAY_SIZE(editor_el_boulderdash_native);
+
+static int editor_hl_boulderdash_effects[] =
+{
+  EL_INTERNAL_CASCADE_BDX_EFFECTS_ACTIVE,
+  EL_CHAR('B'),
+  EL_CHAR('D'),
+  EL_CHAR('E'),
+};
+
+static int editor_el_boulderdash_effects[] =
+{
+  EL_BDX_DIAMOND_FALLING,
+  EL_BDX_ROCK_FALLING,
+  EL_BDX_MEGA_ROCK_FALLING,
+  EL_BDX_FLYING_DIAMOND_FLYING,
+
+  EL_BDX_FALLING_WALL_FALLING,
+  EL_BDX_NITRO_PACK_FALLING,
+  EL_BDX_NUT_FALLING,
+  EL_BDX_FLYING_ROCK_FLYING,
+
+  EL_BDX_PLAYER_GROWING_1,
+  EL_BDX_PLAYER_GROWING_2,
+  EL_BDX_PLAYER_GROWING_3,
+  EL_BDX_PLAYER,
+
+  EL_BDX_PLAYER_WITH_BOMB,
+  EL_BDX_PLAYER_STIRRING,
+  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_BLADDER_5,
+  EL_BDX_BLADDER_6,
+  EL_BDX_BLADDER_7,
+  EL_BDX_BLADDER_8,
+
+  EL_BDX_SAND_2,
+  EL_BDX_COW_ENCLOSED_1,
+  EL_BDX_COW_ENCLOSED_2,
+  EL_BDX_COW_ENCLOSED_3,
+
+  EL_BDX_COW_ENCLOSED_4,
+  EL_BDX_COW_ENCLOSED_5,
+  EL_BDX_COW_ENCLOSED_6,
+  EL_BDX_COW_ENCLOSED_7,
+
+  EL_BDX_WATER_1,
+  EL_BDX_WATER_2,
+  EL_BDX_WATER_3,
+  EL_BDX_WATER_4,
+
+  EL_BDX_WATER_5,
+  EL_BDX_WATER_6,
+  EL_BDX_WATER_7,
+  EL_BDX_WATER_8,
+
+  EL_BDX_WATER_9,
+  EL_BDX_WATER_10,
+  EL_BDX_WATER_11,
+  EL_BDX_WATER_12,
+
+  EL_BDX_WATER_13,
+  EL_BDX_WATER_14,
+  EL_BDX_WATER_15,
+  EL_BDX_WATER_16,
+
+  EL_BDX_BOMB_TICKING_1,
+  EL_BDX_BOMB_TICKING_2,
+  EL_BDX_BOMB_TICKING_3,
+  EL_BDX_BOMB_TICKING_4,
+
+  EL_BDX_BOMB_TICKING_5,
+  EL_BDX_BOMB_TICKING_6,
+  EL_BDX_BOMB_TICKING_7,
+  EL_EMPTY,
+
+  EL_BDX_BOMB_EXPLODING_1,
+  EL_BDX_BOMB_EXPLODING_2,
+  EL_BDX_BOMB_EXPLODING_3,
+  EL_BDX_BOMB_EXPLODING_4,
+
+  EL_BDX_NUT_BREAKING_1,
+  EL_BDX_NUT_BREAKING_2,
+  EL_BDX_NUT_BREAKING_3,
+  EL_BDX_NUT_BREAKING_4,
+
+  EL_BDX_EXPLODING_1,
+  EL_BDX_EXPLODING_2,
+  EL_BDX_EXPLODING_3,
+  EL_BDX_EXPLODING_4,
+
+  EL_BDX_EXPLODING_5,
+  EL_BDX_TIME_PENALTY,
+  EL_BDX_DIAMOND_GROWING_1,
+  EL_BDX_DIAMOND_GROWING_2,
+
+  EL_BDX_DIAMOND_GROWING_3,
+  EL_BDX_DIAMOND_GROWING_4,
+  EL_BDX_DIAMOND_GROWING_5,
+  EL_BDX_NITRO_PACK_EXPLODING,
+
+  EL_BDX_NITRO_PACK_EXPLODING_1,
+  EL_BDX_NITRO_PACK_EXPLODING_2,
+  EL_BDX_NITRO_PACK_EXPLODING_3,
+  EL_BDX_NITRO_PACK_EXPLODING_4,
+
+  EL_BDX_ROCK_GROWING_1,
+  EL_BDX_ROCK_GROWING_2,
+  EL_BDX_ROCK_GROWING_3,
+  EL_BDX_ROCK_GROWING_4,
+
+  EL_BDX_STEELWALL_GROWING_1,
+  EL_BDX_STEELWALL_GROWING_2,
+  EL_BDX_STEELWALL_GROWING_3,
+  EL_BDX_STEELWALL_GROWING_4,
+
+  EL_BDX_CLOCK_GROWING_1,
+  EL_BDX_CLOCK_GROWING_2,
+  EL_BDX_CLOCK_GROWING_3,
+  EL_BDX_CLOCK_GROWING_4,
+
+  EL_BDX_GHOST_EXPLODING_1,
+  EL_BDX_GHOST_EXPLODING_2,
+  EL_BDX_GHOST_EXPLODING_3,
+  EL_BDX_GHOST_EXPLODING_4,
+};
+static int *editor_hl_boulderdash_effects_ptr = editor_hl_boulderdash_effects;
+static int *editor_el_boulderdash_effects_ptr = editor_el_boulderdash_effects;
+static int num_editor_hl_boulderdash_effects = ARRAY_SIZE(editor_hl_boulderdash_effects);
+static int num_editor_el_boulderdash_effects = ARRAY_SIZE(editor_el_boulderdash_effects);
+
 static int editor_hl_emerald_mine[] =
 {
   EL_INTERNAL_CASCADE_EM_ACTIVE,
@@ -4603,7 +6405,12 @@ static int editor_el_mirror_magic[] =
   EL_MM_WOODEN_GRID_FIXED_1,
   EL_MM_WOODEN_GRID_FIXED_2,
   EL_MM_WOODEN_GRID_FIXED_3,
-  EL_MM_WOODEN_GRID_FIXED_4
+  EL_MM_WOODEN_GRID_FIXED_4,
+
+  EL_MM_ENVELOPE_1,
+  EL_MM_ENVELOPE_2,
+  EL_MM_ENVELOPE_3,
+  EL_MM_ENVELOPE_4
 };
 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
@@ -4632,8 +6439,8 @@ static int editor_el_deflektor[] =
 
   EL_DF_MIRROR_START,
   EL_DF_MIRROR_ROTATING_START,
+  EL_DF_MIRROR_FIXED_START,
   EL_DF_CELL,
-  EL_DF_MINE,
 
   EL_DF_FIBRE_OPTIC_RED_1,
   EL_DF_FIBRE_OPTIC_YELLOW_1,
@@ -4648,7 +6455,12 @@ static int editor_el_deflektor[] =
   EL_DF_STEEL_WALL,
   EL_DF_WOODEN_WALL,
   EL_DF_REFRACTOR,
-  EL_EMPTY
+  EL_DF_MINE,
+
+  EL_DF_SLOPE_1,
+  EL_DF_SLOPE_2,
+  EL_DF_SLOPE_3,
+  EL_DF_SLOPE_4
 };
 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
 static int *editor_el_deflektor_ptr = editor_el_deflektor;
@@ -5265,6 +7077,41 @@ static int *editor_el_group_ptr = editor_el_group;
 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
 
+static int editor_hl_empty_space[] =
+{
+  EL_INTERNAL_CASCADE_ES_ACTIVE,
+  EL_CHAR('E'),
+  EL_CHAR('S'),
+  EL_EMPTY,
+};
+
+static int editor_el_empty_space[] =
+{
+  EL_EMPTY_SPACE_1,
+  EL_EMPTY_SPACE_2,
+  EL_EMPTY_SPACE_3,
+  EL_EMPTY_SPACE_4,
+
+  EL_EMPTY_SPACE_5,
+  EL_EMPTY_SPACE_6,
+  EL_EMPTY_SPACE_7,
+  EL_EMPTY_SPACE_8,
+
+  EL_EMPTY_SPACE_9,
+  EL_EMPTY_SPACE_10,
+  EL_EMPTY_SPACE_11,
+  EL_EMPTY_SPACE_12,
+
+  EL_EMPTY_SPACE_13,
+  EL_EMPTY_SPACE_14,
+  EL_EMPTY_SPACE_15,
+  EL_EMPTY_SPACE_16
+};
+static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
+static int *editor_el_empty_space_ptr = editor_el_empty_space;
+static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
+static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
+
 static int editor_hl_reference[] =
 {
   EL_INTERNAL_CASCADE_REF_ACTIVE,
@@ -5353,6 +7200,8 @@ static boolean setup_editor_cascade_never = FALSE;
 
 static boolean setup_editor_el_players                 = TRUE;
 static boolean setup_editor_el_boulderdash             = TRUE;
+static boolean setup_editor_el_boulderdash_native      = TRUE;
+static boolean setup_editor_el_boulderdash_effects     = TRUE;
 static boolean setup_editor_el_emerald_mine            = TRUE;
 static boolean setup_editor_el_emerald_mine_club       = TRUE;
 static boolean setup_editor_el_more                    = TRUE;
@@ -5399,6 +7248,18 @@ editor_elements_info[] =
     &editor_hl_boulderdash_ptr,                &num_editor_hl_boulderdash,
     &editor_el_boulderdash_ptr,                &num_editor_el_boulderdash
   },
+  {
+    &setup_editor_el_boulderdash_native,
+    &setup.editor_cascade.el_bdx,
+    &editor_hl_boulderdash_native_ptr, &num_editor_hl_boulderdash_native,
+    &editor_el_boulderdash_native_ptr, &num_editor_el_boulderdash_native
+  },
+  {
+    &setup_editor_el_boulderdash_effects,
+    &setup.editor_cascade.el_bdx_effects,
+    &editor_hl_boulderdash_effects_ptr,        &num_editor_hl_boulderdash_effects,
+    &editor_el_boulderdash_effects_ptr,        &num_editor_el_boulderdash_effects
+  },
   {
     &setup_editor_el_emerald_mine,
     &setup.editor_cascade.el_em,
@@ -5477,6 +7338,12 @@ editor_elements_info[] =
     &editor_hl_group_ptr,              &num_editor_hl_group,
     &editor_el_group_ptr,              &num_editor_el_group
   },
+  {
+    &setup_editor_el_custom,
+    &setup.editor_cascade.el_es,
+    &editor_hl_empty_space_ptr,                &num_editor_hl_empty_space,
+    &editor_el_empty_space_ptr,                &num_editor_el_empty_space
+  },
   {
     &setup_editor_el_custom,
     &setup.editor_cascade.el_ref,
@@ -5509,11 +7376,24 @@ editor_elements_info[] =
   }
 };
 
+static struct XY xy_directions[] =
+{
+  { -1,  0 },
+  { +1,  0 },
+  {  0, -1 },
+  {  0, +1 }
+};
+
 
 // ----------------------------------------------------------------------------
 // functions
 // ----------------------------------------------------------------------------
 
+boolean isLevelEditorTestGame(void)
+{
+  return level_editor_test_game;
+}
+
 static int getMaxInfoTextLength(void)
 {
   return (SXSIZE / getFontWidth(INFOTEXT_FONT));
@@ -5532,7 +7412,7 @@ static int getTextWidthForDrawingArea(char *text)
   if (text == NULL)
     return 0;
 
-  return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
+  return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_BORDER_SIZE);
 }
 
 static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
@@ -5562,7 +7442,7 @@ static char *getElementInfoText(int element)
 
 static char *getElementDescriptionFilenameExt(char *basename)
 {
-  char *elements_subdir = "elements";
+  char *elements_subdir = ELEMENTS_DIRECTORY;
   static char *elements_subdir2 = NULL;
   static char *filename = NULL;
 
@@ -5603,6 +7483,11 @@ static char *getElementDescriptionFilename(int element)
   if (filename != NULL)
     return filename;
 
+  // 3rd try: look for generic fallback text file for any element
+  filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
+  if (filename != NULL)
+    return filename;
+
   return NULL;
 }
 
@@ -5624,9 +7509,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   // find all elements used in current level
   for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
-      if (Tile[x][y] < NUM_FILE_ELEMENTS)      // should always be true
+    {
+      if (Tile[x][y] >= NUM_FILE_ELEMENTS)     // should never happen
+       continue;
+
+      if (IS_MM_WALL(Tile[x][y]))
+       element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
+      else
        element_found[Tile[x][y]] = TRUE;
+    }
+  }
 
   *num_elements = 0;
 
@@ -5646,14 +7540,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   *num_elements = 0;
 
-  // add all elements used in current level (non-custom/group elements)
+  // add all elements used in current level (non-custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
+                             IS_GROUP_ELEMENT(i) ||
+                             IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
-  // add all elements used in current level (custom/group elements)
+  // add all elements used in current level (custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
+                            IS_GROUP_ELEMENT(i) ||
+                            IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
   while (*num_elements % 4)    // pad with empty elements, if needed
@@ -5666,6 +7564,8 @@ static void ReinitializeElementList_EnableSections(void)
 
   setup_editor_el_players              = TRUE;
   setup_editor_el_boulderdash          = TRUE;
+  setup_editor_el_boulderdash_native   = TRUE;
+  setup_editor_el_boulderdash_effects  = TRUE;
   setup_editor_el_emerald_mine         = TRUE;
   setup_editor_el_emerald_mine_club    = TRUE;
   setup_editor_el_more                 = TRUE;
@@ -5688,6 +7588,8 @@ static void ReinitializeElementList_EnableSections(void)
   {
     setup_editor_el_players            = FALSE;
     setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_boulderdash_native = FALSE;
+    setup_editor_el_boulderdash_effects        = FALSE;
     setup_editor_el_emerald_mine       = FALSE;
     setup_editor_el_emerald_mine_club  = FALSE;
     setup_editor_el_more               = FALSE;
@@ -5718,12 +7620,34 @@ static void ReinitializeElementList_EnableSections(void)
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
   {
+    setup_editor_el_boulderdash_native = FALSE;
+    setup_editor_el_boulderdash_effects        = FALSE;
+    setup_editor_el_mirror_magic       = FALSE;
+    setup_editor_el_deflektor          = FALSE;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    setup_editor_el_players            = FALSE;
+    setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_emerald_mine       = FALSE;
+    setup_editor_el_emerald_mine_club  = FALSE;
+    setup_editor_el_more               = FALSE;
+    setup_editor_el_sokoban            = FALSE;
+    setup_editor_el_supaplex           = FALSE;
+    setup_editor_el_diamond_caves      = FALSE;
+    setup_editor_el_dx_boulderdash     = FALSE;
     setup_editor_el_mirror_magic       = FALSE;
     setup_editor_el_deflektor          = FALSE;
+    setup_editor_el_chars              = FALSE;
+    setup_editor_el_steel_chars                = FALSE;
+
+    setup_editor_el_custom             = FALSE;
   }
   else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_boulderdash_native = FALSE;
+    setup_editor_el_boulderdash_effects        = FALSE;
     setup_editor_el_more               = FALSE;
     setup_editor_el_sokoban            = FALSE;
     setup_editor_el_supaplex           = FALSE;
@@ -5739,6 +7663,8 @@ static void ReinitializeElementList_EnableSections(void)
   {
     setup_editor_el_players            = FALSE;
     setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_boulderdash_native = FALSE;
+    setup_editor_el_boulderdash_effects        = FALSE;
     setup_editor_el_emerald_mine       = FALSE;
     setup_editor_el_emerald_mine_club  = FALSE;
     setup_editor_el_more               = FALSE;
@@ -5756,6 +7682,8 @@ static void ReinitializeElementList_EnableSections(void)
   {
     setup_editor_el_players            = FALSE;
     setup_editor_el_boulderdash                = FALSE;
+    setup_editor_el_boulderdash_native = FALSE;
+    setup_editor_el_boulderdash_effects        = FALSE;
     setup_editor_el_emerald_mine       = FALSE;
     setup_editor_el_emerald_mine_club  = FALSE;
     setup_editor_el_more               = FALSE;
@@ -5831,10 +7759,10 @@ static void ReinitializeElementList(void)
   // determine size of element list
   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
   {
-    boolean found_inactive_cascade = FALSE;
-
     if (*editor_elements_info[i].setup_value)
     {
+      boolean found_inactive_cascade = FALSE;
+
       if (setup.editor.el_headlines)
       {
        // required for correct padding of palette headline buttons
@@ -6126,11 +8054,21 @@ static void DrawDrawingArea(int id)
   int tilesize = ED_DRAWINGAREA_TILE_SIZE;
 
   for (x = 0; x < area_xsize; x++)
+  {
     for (y = 0; y < area_ysize; y++)
+    {
+      int element = value[x * area_ysize + y];
+      int graphic;
+      int frame;
+
+      el2edimg_with_frame(element, &graphic, &frame);
+
       DrawSizedGraphicExt(drawto,
                          gi->x + x * tilesize,
                          gi->y + y * tilesize,
-                         el2edimg(value[x * area_ysize + y]), 0, tilesize);
+                         graphic, frame, tilesize);
+    }
+  }
 }
 
 static void ScrollEditorLevel(int from_x, int from_y, int scroll)
@@ -6167,7 +8105,12 @@ static void ScrollEditorLevel(int from_x, int from_y, int scroll)
 static void getEditorGraphicSource(int element, int tile_size, Bitmap **bitmap,
                                   int *x, int *y)
 {
-  getSizedGraphicSource(el2edimg(element), 0, tile_size, bitmap, x, y);
+  int graphic;
+  int frame;
+
+  el2edimg_with_frame(element, &graphic, &frame);
+
+  getSizedGraphicSource(graphic, frame, tile_size, bitmap, x, y);
 }
 
 static void CreateControlButtons(void)
@@ -6178,6 +8121,7 @@ static void CreateControlButtons(void)
   // create toolbox buttons
   for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
   {
+    int type_id = controlbutton_info[i].gadget_id;     // same as gadget ID here
     int id = controlbutton_info[i].gadget_id;
     int type = controlbutton_info[i].gadget_type;
     int graphic = controlbutton_info[i].graphic;
@@ -6201,6 +8145,9 @@ static void CreateControlButtons(void)
     int radio_button_nr = RADIO_NR_NONE;
     boolean checked = FALSE;
 
+    if (type_id != i)
+      Fail("'controlbutton_info' structure corrupted at index %d -- please fix", i);
+
     if (type == GD_TYPE_RADIO_BUTTON)
     {
       event_mask = GD_EVENT_PRESSED;
@@ -6261,7 +8208,7 @@ static void CreateControlButtons(void)
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, controlbutton_info[i].infotext,
                      GDI_X, x,
@@ -6310,6 +8257,7 @@ static void CreateControlButtons(void)
   for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
   {
     int id = scrollbutton_info[i].gadget_id;
+    int type_id = scrollbutton_info[i].gadget_type_id;
     int graphic = scrollbutton_info[i].graphic;
     struct GraphicInfo *gd = &graphic_info[graphic];
     Bitmap *gd_bitmap = gd->bitmap;
@@ -6323,6 +8271,9 @@ static void CreateControlButtons(void)
     int y = scrollbutton_pos[i].y;
     unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
+    if (type_id != i)
+      Fail("'scrollbutton_info' structure corrupted at index %d -- please fix", i);
+
     if (id == GADGET_ID_SCROLL_LIST_UP ||
        id == GADGET_ID_SCROLL_LIST_DOWN)
     {
@@ -6336,7 +8287,7 @@ static void CreateControlButtons(void)
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, scrollbutton_info[i].infotext,
                      GDI_X, x,
@@ -6361,6 +8312,7 @@ static void CreateControlButtons(void)
   // create buttons for element list
   for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
   {
+    int type_id = i;
     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
     int graphic = IMG_EDITOR_PALETTE_BUTTON;
     struct GraphicInfo *gd = &graphic_info[graphic];
@@ -6385,7 +8337,7 @@ static void CreateControlButtons(void)
     deco_ypos = (gd->height - tile_size) / 2;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, getElementInfoText(element),
                      GDI_X, x,
@@ -6419,9 +8371,13 @@ static void CreateCounterButtons(void)
 
   for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
   {
-    int j;
+    int type_id = counterbutton_info[i].gadget_type_id;
     int x = SX + ED_SETTINGS_X(counterbutton_info[i].x); // down count button
     int y = SY + ED_SETTINGS_Y(counterbutton_info[i].y);
+    int j;
+
+    if (type_id != i)
+      Fail("'counterbutton_info' structure corrupted at index %d -- please fix", i);
 
     // determine horizontal position to the right of specified gadget
     if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -6441,11 +8397,9 @@ static void CreateCounterButtons(void)
       int graphic;
       struct GraphicInfo *gd;
       int gd_x1, gd_x2, gd_y1, gd_y2;
-      unsigned int event_mask;
+      unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
       char infotext[max_infotext_len + 1];
 
-      event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
-
       if (i == ED_COUNTER_ID_SELECT_LEVEL)
       {
        graphic = (j == 0 ?
@@ -6480,10 +8434,10 @@ static void CreateCounterButtons(void)
       gd_y2 = gd->src_y + gd->pressed_yoffset;
 
       sprintf(infotext, "%s counter value by 1, 5 or 10",
-             (j == 0 ? "decrease" : "increase"));
+             (j == 0 ? "Decrease" : "Increase"));
 
       gi = CreateGadget(GDI_CUSTOM_ID, id,
-                       GDI_CUSTOM_TYPE_ID, i,
+                       GDI_CUSTOM_TYPE_ID, type_id,
                        GDI_IMAGE_ID, graphic,
                        GDI_INFO_TEXT, infotext,
                        GDI_X, x,
@@ -6540,9 +8494,9 @@ static void CreateCounterButtons(void)
        gd_y2 = gd->src_y + gd->active_yoffset;
 
        gi = CreateGadget(GDI_CUSTOM_ID, id,
-                         GDI_CUSTOM_TYPE_ID, i,
+                         GDI_CUSTOM_TYPE_ID, type_id,
                          GDI_IMAGE_ID, graphic,
-                         GDI_INFO_TEXT, "enter counter value",
+                         GDI_INFO_TEXT, "Enter counter value",
                          GDI_X, x,
                          GDI_Y, y,
                          GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC,
@@ -6585,19 +8539,21 @@ static void CreateDrawingAreas(void)
   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
   {
     struct GadgetInfo *gi;
-    unsigned int event_mask;
     int id = drawingarea_info[i].gadget_id;
+    int type_id = drawingarea_info[i].gadget_type_id;
     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
     int area_xsize = drawingarea_info[i].area_xsize;
     int area_ysize = drawingarea_info[i].area_ysize;
     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
                     ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
-
-    event_mask =
+    unsigned int event_mask =
       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
 
+    if (type_id != i)
+      Fail("'drawingarea_info' structure corrupted at index %d -- please fix", i);
+
     // determine horizontal position to the right of specified gadget
     if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
@@ -6608,7 +8564,7 @@ static void CreateDrawingAreas(void)
       x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_X, x,
                      GDI_Y, y,
                      GDI_TYPE, GD_TYPE_DRAWING_AREA,
@@ -6641,11 +8597,15 @@ static void CreateTextInputGadgets(void)
     int gd_x2 = gd->src_x + gd->active_xoffset;
     int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textinput_info[i].gadget_id;
+    int type_id = textinput_info[i].gadget_type_id;
     int x, y;
 
+    if (type_id != i)
+      Fail("'textinput_info' structure corrupted at index %d -- please fix", i);
+
     if (i == ED_TEXTINPUT_ID_ELEMENT_NAME)
     {
       int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
@@ -6668,13 +8628,15 @@ static void CreateTextInputGadgets(void)
       y = ED_SETTINGS_Y(textinput_info[i].y);
     }
 
-    event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
+    // determine horizontal offset for leading text
+    if (textinput_info[i].text_left != NULL)
+      x += getTextWidthForGadget(textinput_info[i].text_left);
 
-    sprintf(infotext, "Enter %s", textinput_info[i].infotext);
+    sprintf(infotext, "%s", textinput_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_INFO_TEXT, infotext,
                      GDI_X, SX + x,
                      GDI_Y, SY + y,
@@ -6712,19 +8674,21 @@ static void CreateTextAreaGadgets(void)
     int gd_x2 = gd->src_x + gd->active_xoffset;
     int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textarea_info[i].gadget_id;
+    int type_id = textarea_info[i].gadget_type_id;
     int area_xsize = textarea_info[i].xsize;
     int area_ysize = textarea_info[i].ysize;
 
-    event_mask = GD_EVENT_TEXT_LEAVING;
+    if (type_id != i)
+      Fail("'textarea_info' structure corrupted at index %d -- please fix", i);
 
     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_INFO_TEXT, infotext,
                      GDI_X, SX + ED_SETTINGS_X(textarea_info[i].x),
                      GDI_Y, SY + ED_SETTINGS_Y(textarea_info[i].y),
@@ -6751,6 +8715,7 @@ static void CreateTextAreaGadgets(void)
 static void CreateSelectboxGadgets(void)
 {
   int max_infotext_len = getMaxInfoTextLength();
+
   int i, j;
 
   for (i = 0; i < ED_NUM_SELECTBOX; i++)
@@ -6763,11 +8728,16 @@ static void CreateSelectboxGadgets(void)
     int gd_y2 = gd->src_y + gd->active_yoffset;
     int selectbox_button_xsize = gd2->width;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = selectbox_info[i].gadget_id;
+    int type_id = selectbox_info[i].gadget_type_id;
     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
+    unsigned int event_mask =
+      GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
+
+    if (type_id != i)
+      Fail("'selectbox_info' structure corrupted at index %d -- please fix", i);
 
     if (selectbox_info[i].size == -1)  // dynamically determine size
     {
@@ -6783,9 +8753,6 @@ static void CreateSelectboxGadgets(void)
       selectbox_info[i].size++;                // add one character empty space
     }
 
-    event_mask = GD_EVENT_RELEASED |
-      GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
     // determine horizontal position to the right of specified gadget
     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
@@ -6795,11 +8762,11 @@ static void CreateSelectboxGadgets(void)
     if (selectbox_info[i].text_left != NULL)
       x += getTextWidthForGadget(selectbox_info[i].text_left);
 
-    sprintf(infotext, "Select %s", selectbox_info[i].infotext);
+    sprintf(infotext, "%s", selectbox_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_INFO_TEXT, infotext,
                      GDI_X, x,
                      GDI_Y, y,
@@ -6837,8 +8804,10 @@ static void CreateTextbuttonGadgets(void)
   for (i = 0; i < ED_NUM_TEXTBUTTONS; i++)
   {
     int id = textbutton_info[i].gadget_id;
+    int type_id = textbutton_info[i].gadget_type_id;
     int is_tab_button =
-      ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
+      ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_ENGINE) ||
+       (id >= GADGET_ID_ENGINECONFIG_CONFIG && id <= GADGET_ID_ENGINECONFIG_COLORS) ||
        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
     int graphic =
       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
@@ -6854,16 +8823,17 @@ static void CreateTextbuttonGadgets(void)
     int border_xsize = gd->border_size + gd->draw_xoffset;
     int border_ysize = gd->border_size;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_RELEASED;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
 
+    if (type_id != i)
+      Fail("'textbutton_info' structure corrupted at index %d -- please fix", i);
+
     if (textbutton_info[i].size == -1) // dynamically determine size
       textbutton_info[i].size = strlen(textbutton_info[i].text);
 
-    event_mask = GD_EVENT_RELEASED;
-
     sprintf(infotext, "%s", textbutton_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6883,7 +8853,7 @@ static void CreateTextbuttonGadgets(void)
       x += getTextWidthForGadget(textbutton_info[i].text_left);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, infotext,
                      GDI_X, x,
@@ -6916,13 +8886,13 @@ static void CreateTextbuttonGadgets(void)
 static void CreateGraphicbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
   // create buttons for scrolling of drawing area and element list
   for (i = 0; i < ED_NUM_GRAPHICBUTTONS; i++)
   {
     int id = graphicbutton_info[i].gadget_id;
+    int type_id = graphicbutton_info[i].gadget_type_id;
     int x = SX + ED_SETTINGS_X(graphicbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(graphicbutton_info[i].y);
     int graphic = graphicbutton_info[i].graphic;
@@ -6931,8 +8901,10 @@ static void CreateGraphicbuttonGadgets(void)
     int gd_y1 = gd->src_y;
     int gd_x2 = gd->src_x + gd->pressed_xoffset;
     int gd_y2 = gd->src_y + gd->pressed_yoffset;
+    unsigned int event_mask = GD_EVENT_RELEASED;
 
-    event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+    if (type_id != i)
+      Fail("'graphicbutton_info' structure corrupted at index %d -- please fix", i);
 
     // determine horizontal position to the right of specified gadget
     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -6944,7 +8916,7 @@ static void CreateGraphicbuttonGadgets(void)
       x += getTextWidthForGadget(graphicbutton_info[i].text_left);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, graphicbutton_info[i].infotext,
                      GDI_X, x,
@@ -7016,6 +8988,7 @@ static void CreateScrollbarGadgets(void)
   for (i = 0; i < ED_NUM_SCROLLBARS; i++)
   {
     int id = scrollbar_info[i].gadget_id;
+    int type_id = scrollbar_info[i].gadget_type_id;
     int graphic = scrollbar_info[i].graphic;
     struct GraphicInfo *gd = &graphic_info[graphic];
     int gd_x1 = gd->src_x;
@@ -7024,7 +8997,10 @@ static void CreateScrollbarGadgets(void)
     int gd_y2 = gd->src_y + gd->pressed_yoffset;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+
+    if (type_id != i)
+      Fail("'scrollbar_info' structure corrupted at index %d -- please fix", i);
 
     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
     {
@@ -7048,10 +9024,8 @@ static void CreateScrollbarGadgets(void)
       }
     }
 
-    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
-
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, scrollbar_info[i].infotext,
                      GDI_X, scrollbar_pos[i].x,
@@ -7085,14 +9059,12 @@ static void CreateScrollbarGadgets(void)
 static void CreateCheckbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
   {
     int id = checkbutton_info[i].gadget_id;
+    int type_id = checkbutton_info[i].gadget_type_id;
     int graphic = (id == GADGET_ID_STICK_ELEMENT ? IMG_EDITOR_STICKYBUTTON :
                   IMG_EDITOR_CHECKBOX);
     struct GraphicInfo *gd = &graphic_info[graphic];
@@ -7106,6 +9078,10 @@ static void CreateCheckbuttonGadgets(void)
     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
+
+    if (type_id != i)
+      Fail("'checkbutton_info' structure corrupted at index %d -- please fix", i);
 
     // determine horizontal position to the right of specified gadget
     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -7117,7 +9093,7 @@ static void CreateCheckbuttonGadgets(void)
       x += getTextWidthForGadget(checkbutton_info[i].text_left);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, checkbutton_info[i].infotext,
                      GDI_X, x,
@@ -7157,16 +9133,18 @@ static void CreateRadiobuttonGadgets(void)
   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
   {
     int id = radiobutton_info[i].gadget_id;
+    int type_id = radiobutton_info[i].gadget_type_id;
     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
+
+    if (type_id != i)
+      Fail("'radiobutton_info' structure corrupted at index %d -- please fix", i);
 
     int checked =
       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
@@ -7181,7 +9159,7 @@ static void CreateRadiobuttonGadgets(void)
       x += getTextWidthForGadget(radiobutton_info[i].text_left);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_CUSTOM_TYPE_ID, type_id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, radiobutton_info[i].infotext,
                      GDI_X, x,
@@ -7235,6 +9213,8 @@ void CreateLevelEditorGadgets(void)
 
   use_permanent_palette = !editor.palette.show_as_separate_screen;
 
+  InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
+
   ReinitializeElementList();
 
   CreateControlButtons();
@@ -7302,16 +9282,12 @@ static void MapCounterButtons(int id)
 
   ModifyEditorCounterValue(id, *counterbutton_info[id].value);
 
-  // set position for "value[1,2,3,4]" counter gadgets (score in most cases)
-  if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
-      id <= ED_COUNTER_ID_ELEMENT_VALUE4)
+  // set position for counter gadgets with dynamically determined position
+  if (id != ED_COUNTER_ID_SELECT_LEVEL)
   {
-    ModifyGadget(gi_down, GDI_Y,
-                SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
-    ModifyGadget(gi_text, GDI_Y,
-                SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
-    ModifyGadget(gi_up,   GDI_Y,
-                SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
+    ModifyGadget(gi_down, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
+    ModifyGadget(gi_text, GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
+    ModifyGadget(gi_up,   GDI_Y, SY + ED_SETTINGS_Y(counterbutton_info[id].y), GDI_END);
   }
 
   // vertical position might have changed after setting position above
@@ -7370,7 +9346,7 @@ static void MapDrawingArea(int id)
   int area_ysize = gi->drawing.area_ysize;
   int xoffset_left = getTextWidthForDrawingArea(drawingarea_info[id].text_left);
   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
-  int x_left  = gi->x - xoffset_left;
+  int x_left  = gi->x - xoffset_left - ED_DRAWINGAREA_BORDER_SIZE;
   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
   int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
   int x_below = gi->x + (gi->width - xoffset_below) / 2;
@@ -7407,12 +9383,23 @@ static void MapTextInputGadget(int id)
   int font_nr = FONT_TEXT_1;
   int font_height = getFontHeight(font_nr);
   struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
+  int xoffset_left = getTextWidthForGadget(textinput_info[id].text_left);
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
-  int x_above = ED_SETTINGS_X(textinput_info[id].x);
-  int y_above = ED_SETTINGS_Y(textinput_info[id].y) - yoffset_above;
+  int yoffset = (gi->height - font_height) / 2;
+  int x_left = gi->x - xoffset_left;
+  int x_right = gi->x + gi->width + xoffset_right;
+  int y_above = gi->y - yoffset_above;
+  int y = gi->y + yoffset;
 
   if (textinput_info[id].text_above)
-    DrawTextS(x_above, y_above, font_nr, textinput_info[id].text_above);
+    DrawText(x_left, y_above, textinput_info[id].text_above, font_nr);
+
+  if (textinput_info[id].text_left)
+    DrawText(x_left, y, textinput_info[id].text_left, font_nr);
+
+  if (textinput_info[id].text_right)
+    DrawText(x_right, y, textinput_info[id].text_right, font_nr);
 
   ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
 
@@ -7427,9 +9414,13 @@ static void MapTextAreaGadget(int id)
   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
   int x_above = ED_SETTINGS_X(textarea_info[id].x);
   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
+  char *text_above = textarea_info[id].text_above;
+
+  if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
+    text_above = textarea_info[id].text_above_cropped;
 
-  if (textarea_info[id].text_above)
-    DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above);
+  if (text_above)
+    DrawTextS(x_above, y_above, font_nr, text_above);
 
   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
 
@@ -7448,11 +9439,10 @@ static void MapSelectboxGadget(int id)
   int x_left = gi->x - xoffset_left;
   int x_right = gi->x + gi->width + xoffset_right;
   int y_above = gi->y - yoffset_above;
-  int x = gi->x;
   int y = gi->y + yoffset;
 
   if (selectbox_info[id].text_above)
-    DrawText(x, y_above, selectbox_info[id].text_above, font_nr);
+    DrawText(x_left, y_above, selectbox_info[id].text_above, font_nr);
 
   if (selectbox_info[id].text_left)
     DrawText(x_left, y, selectbox_info[id].text_left, font_nr);
@@ -7501,7 +9491,7 @@ static void MapGraphicbuttonGadget(int id)
 {
   int font_nr = FONT_TEXT_1;
   int font_height = getFontHeight(font_nr);
-  struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id];
+  struct GadgetInfo *gi = level_editor_gadget[graphicbutton_info[id].gadget_id];
   int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left);
   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
   int yoffset = (gi->height - font_height) / 2;
@@ -7558,7 +9548,7 @@ static void MapCheckbuttonGadget(int id)
 
   // set position for gadgets with dynamically determined position
   if (checkbutton_info[id].x != -1)    // do not change dynamic positions
-    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END);
+    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
 
   x_left = gi->x - xoffset_left;
@@ -7591,7 +9581,7 @@ static void MapMainDrawingArea(void)
     no_vertical_scrollbar   = (lev_fieldy <= ed_fieldy);
   }
 
-  for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
+  for (i = ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
   {
     if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
          i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
@@ -7641,6 +9631,14 @@ static void MapLevelEditorToolboxCustomGadgets(void)
   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
 }
 
+static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
+{
+  if (IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element) ||
+      IS_EMPTY_ELEMENT(properties_element))
+    MapLevelEditorToolboxCustomGadgets();
+}
+
 static void UnmapLevelEditorToolboxCustomGadgets(void)
 {
   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
@@ -7729,8 +9727,8 @@ static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
     RedrawDrawingElements();
   }
 
-  if (edit_mode == ED_MODE_INFO)
-    DrawLevelInfoWindow();
+  if (edit_mode == ED_MODE_LEVELCONFIG)
+    DrawLevelConfigWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
     DrawPropertiesWindow();
   else if (edit_mode == ED_MODE_PALETTE)
@@ -7830,7 +9828,7 @@ static boolean PrepareSavingIntoPersonalLevelSet(void)
   return TRUE;
 }
 
-static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
+static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
 {
   static char *filename_levelinfo = NULL, *mod_name = NULL;
   FILE *file;
@@ -8063,6 +10061,12 @@ static boolean CopyCustomElement(int element_old, int element_new,
 
     return FALSE;
   }
+  else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
+  {
+    Request("Please choose empty element!", REQ_CONFIRM);
+
+    return FALSE;
+  }
   else
   {
     level.changed = TRUE;
@@ -8205,7 +10209,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
 
   // set "change by direct action" selectbox help value
   custom_element_change.direct_action =
-    (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
+    (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
@@ -8229,7 +10234,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
 
   // set "change by other element action" selectbox help value
   custom_element_change.other_action =
-    (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
+    (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
+     HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
@@ -8239,6 +10245,7 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
+     HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
@@ -8263,6 +10270,11 @@ static void CopyGroupElementPropertiesToEditor(int element)
   custom_element = element_info[element];      // needed for description
 }
 
+static void CopyEmptyElementPropertiesToEditor(int element)
+{
+  custom_element = element_info[element];
+}
+
 static void CopyClassicElementPropertiesToEditor(int element)
 {
   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
@@ -8280,6 +10292,8 @@ static void CopyElementPropertiesToEditor(int element)
     CopyCustomElementPropertiesToEditor(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToEditor(element);
+  else if (IS_EMPTY_ELEMENT(element))
+    CopyEmptyElementPropertiesToEditor(element);
   else
     CopyClassicElementPropertiesToEditor(element);
 }
@@ -8367,6 +10381,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   // ---------- element settings: advanced (custom elements) ------------------
 
   // set player change event from checkbox and selectbox
+  custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
@@ -8391,6 +10406,7 @@ static void CopyCustomElementPropertiesToGame(int element)
     custom_element_change_events[CE_BY_DIRECT_ACTION];
 
   // set other element action change event from checkbox and selectbox
+  custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
@@ -8401,6 +10417,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
+  custom_element_change_events[CE_NEXT_TO_X] = FALSE;
   custom_element_change_events[CE_TOUCHING_X] = FALSE;
   custom_element_change_events[CE_HITTING_X] = FALSE;
   custom_element_change_events[CE_DIGGING_X] = FALSE;
@@ -8449,6 +10466,21 @@ static void CopyGroupElementPropertiesToGame(int element)
   InitElementPropertiesGfxElement();
 }
 
+static void CopyEmptyElementPropertiesToGame(int element)
+{
+  // mark that this empty element has been modified
+  custom_element.modified_settings = TRUE;
+  level.changed = TRUE;
+
+  if (level.use_custom_template)
+    AskToCopyAndModifyLevelTemplate();
+
+  element_info[element] = custom_element;
+
+  // needed here to restore runtime value "element_info[element].gfx_element"
+  InitElementPropertiesGfxElement();
+}
+
 static void CopyClassicElementPropertiesToGame(int element)
 {
   if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
@@ -8466,6 +10498,8 @@ static void CopyElementPropertiesToGame(int element)
     CopyCustomElementPropertiesToGame(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToGame(element);
+  else if (IS_EMPTY_ELEMENT(element))
+    CopyEmptyElementPropertiesToGame(element);
   else
     CopyClassicElementPropertiesToGame(element);
 }
@@ -8540,24 +10574,10 @@ static void InitDrawingElements(void)
   if (level.game_engine_type == game_engine_type_last)
     return;
 
-  if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
-  {
-    new_element1 = EL_SP_CHIP_SINGLE;
-    new_element2 = EL_EMPTY;
-    new_element3 = EL_SP_BASE;
-  }
-  else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
-  {
-    new_element1 = EL_MM_MIRROR_START;
-    new_element2 = EL_EMPTY;
-    new_element3 = EL_MM_WOODEN_WALL;
-  }
-  else
-  {
-    new_element1 = EL_WALL;
-    new_element2 = EL_EMPTY;
-    new_element3 = EL_SAND;
-  }
+  // select drawing elements according to game engine type
+  new_element1 = getDrawingElement(EL_WALL);
+  new_element2 = getDrawingElement(EL_EMPTY);
+  new_element3 = getDrawingElement(EL_SAND);
 
   game_engine_type_last = level.game_engine_type;
 }
@@ -8643,6 +10663,15 @@ static void DrawEditorDoorContent(void)
   // draw all toolbox gadgets to editor doors
   MapControlButtons();
 
+  // when returning from test game to properties page, redraw toolbox gadgets
+  if (edit_mode == ED_MODE_PROPERTIES)
+  {
+    UnmapLevelEditorToolboxDrawingGadgets();
+    UnmapLevelEditorToolboxCustomGadgets();
+
+    MapLevelEditorToolboxCustomGadgetsIfNeeded();
+  }
+
   // draw all palette gadgets to editor doors
   ModifyEditorElementList();
   RedrawDrawingElements();
@@ -8685,7 +10714,8 @@ void DrawLevelEd(void)
   else
   {
     edit_mode = ED_MODE_DRAWING;
-    edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
+    edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
+    edit_mode_engineconfig = ED_MODE_ENGINECONFIG_CONFIG;
     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
 
     ResetUndoBuffer();
@@ -8741,8 +10771,8 @@ static void AdjustDrawingAreaGadgets(void)
 
   if (suppressBorderElement())
   {
-    ed_xsize = max_ed_fieldx;
-    ed_ysize = max_ed_fieldy;
+    ed_xsize = lev_fieldx;
+    ed_ysize = lev_fieldy;
   }
 
   // check if we need any scrollbars
@@ -9068,7 +11098,7 @@ static int getTabulatorBarHeight(void)
 
 static Pixel getTabulatorBarColor(void)
 {
-  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
+  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
   int gd_x = gd->x + gd_gi1->border.width / 2;
   int gd_y = gd->y + gd_gi1->height - 1;
@@ -9076,19 +11106,19 @@ static Pixel getTabulatorBarColor(void)
   return GetPixel(gd->bitmap, gd_x, gd_y);
 }
 
-static void DrawLevelInfoTabulatorGadgets(void)
+static void DrawEngineConfigTabulatorGadgets(void)
 {
-  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
+  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_ENGINECONFIG_CONFIG];
   Pixel tab_color = getTabulatorBarColor();
-  int id_first = ED_TAB_BUTTON_ID_LEVELINFO_FIRST;
-  int id_last  = ED_TAB_BUTTON_ID_LEVELINFO_LAST;
+  int id_first = ED_TEXTBUTTON_ID_ENGINECONFIG_CONFIG;
+  int id_last  = ED_TEXTBUTTON_ID_ENGINECONFIG_COLORS;
   int i;
 
   for (i = id_first; i <= id_last; i++)
   {
     int gadget_id = textbutton_info[i].gadget_id;
     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
-    boolean active = (i != edit_mode_levelinfo);
+    boolean active = (i != edit_mode_engineconfig);
 
     // draw background line below tabulator button
     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
@@ -9109,6 +11139,47 @@ static void DrawLevelInfoTabulatorGadgets(void)
                  getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
 }
 
+static void DrawLevelConfigTabulatorGadgets(void)
+{
+  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
+  Pixel tab_color = getTabulatorBarColor();
+  int id_first = ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL;
+  int id_last  = ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR;
+  int i;
+
+  // draw additional "engine" tabulator when using native BD engine
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    id_last = ED_TEXTBUTTON_ID_LEVELCONFIG_ENGINE;
+
+  for (i = id_first; i <= id_last; i++)
+  {
+    int gadget_id = textbutton_info[i].gadget_id;
+    struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+    boolean active = (i != edit_mode_levelconfig);
+
+    // draw background line below tabulator button
+    ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
+
+    // draw solid line below inactive tabulator buttons
+    if (!active && tab_color != BLACK_PIXEL)   // black => transparent
+      FillRectangle(drawto, gi->x, gi->y + gi->height, gi->width,
+                   ED_GADGET_TINY_DISTANCE, tab_color);
+
+    ModifyGadget(gi, GDI_ACTIVE, active, GDI_END);
+    MapTextbuttonGadget(i);
+  }
+
+  // draw little border line below tabulator buttons
+  if (tab_color != BLACK_PIXEL)                        // black => transparent
+    FillRectangle(drawto, gd_gi1->x, gd_gi1->y + gd_gi1->height +
+                 ED_GADGET_TINY_DISTANCE,
+                 getTabulatorBarWidth(), getTabulatorBarHeight(), tab_color);
+
+  // draw second row of engine related tabulators when using native BD engine
+  if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
+    DrawEngineConfigTabulatorGadgets();
+}
+
 static void DrawPropertiesTabulatorGadgets(void)
 {
   struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
@@ -9177,7 +11248,7 @@ static int PrintElementDescriptionFromFile(char *filename, int font_nr,
                      TRUE, FALSE, FALSE);
 }
 
-static void DrawLevelInfoLevel(void)
+static void DrawLevelConfigLevel(void)
 {
   int i;
 
@@ -9206,7 +11277,7 @@ static char *getLevelSubdirFromSaveMode(int save_mode)
   return leveldir_current->subdir;
 }
 
-static void DrawLevelInfoLevelSet_DirectoryInfo(void)
+static void DrawLevelConfigLevelSet_DirectoryInfo(void)
 {
   char *directory_text = "Level set directory:";
   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
@@ -9221,7 +11292,7 @@ static void DrawLevelInfoLevelSet_DirectoryInfo(void)
   PrintInfoText(directory_name, font2_nr, x, y);
 }
 
-static void DrawLevelInfoLevelSet(void)
+static void DrawLevelConfigLevelSet(void)
 {
   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
@@ -9254,10 +11325,10 @@ static void DrawLevelInfoLevelSet(void)
   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
 
   // draw info text
-  DrawLevelInfoLevelSet_DirectoryInfo();
+  DrawLevelConfigLevelSet_DirectoryInfo();
 }
 
-static void DrawLevelInfoEditor(void)
+static void DrawLevelConfigEditor(void)
 {
   int i;
 
@@ -9266,11 +11337,11 @@ static void DrawLevelInfoEditor(void)
     MapCounterButtons(i);
 
   // draw checkbutton gadgets
-  for (i=ED_CHECKBUTTON_ID_EDITOR_FIRST; i<= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
+  for (i = ED_CHECKBUTTON_ID_EDITOR_FIRST; i <= ED_CHECKBUTTON_ID_EDITOR_LAST; i++)
     MapCheckbuttonGadget(i);
 
   // draw radiobutton gadgets
-  for (i=ED_RADIOBUTTON_ID_EDITOR_FIRST; i<= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
+  for (i = ED_RADIOBUTTON_ID_EDITOR_FIRST; i <= ED_RADIOBUTTON_ID_EDITOR_LAST; i++)
     MapRadiobuttonGadget(i);
 
   // draw drawing area
@@ -9280,7 +11351,171 @@ static void DrawLevelInfoEditor(void)
   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
 }
 
-static void DrawLevelInfoWindow(void)
+static void DrawEngineConfigConfig(void)
+{
+  int i;
+
+  // draw counter gadgets
+  if (level.bd_scheduling_type == GD_SCHEDULING_MILLISECONDS)
+  {
+    MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_MS);
+    MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_CYCLES);
+  }
+  else
+  {
+    MapCounterButtons(ED_COUNTER_ID_BD_CYCLE_DELAY_C64);
+    MapCounterButtons(ED_COUNTER_ID_BD_HATCHING_DELAY_SECONDS);
+  }
+
+  // draw checkbutton gadgets
+  for (i = ED_CHECKBUTTON_ID_ENGINE_FIRST; i <= ED_CHECKBUTTON_ID_ENGINE_LAST; i++)
+    MapCheckbuttonGadget(i);
+
+  // draw selectbox gadgets
+  for (i = ED_SELECTBOX_ID_ENGINE_FIRST; i <= ED_SELECTBOX_ID_ENGINE_LAST; i++)
+    MapSelectboxGadget(i);
+}
+
+static int GetCommonColorType_BD(void)
+{
+  int bd_color_type = *bd_color[0] >> 24;
+  int i;
+
+  // check if all colors have the same color type
+  for (i = 1; i < MAX_BD_COLORS; i++)
+    if ((*bd_color[i] >> 24) != bd_color_type)
+      return GD_COLOR_TYPE_RGB;
+
+  return bd_color_type;
+}
+
+void SetDefaultLevelColorType_BD(void)
+{
+  bd_color_type_default = GetCommonColorType_BD();
+
+  level.bd_color_type = bd_color_type_default;
+}
+
+void SetDefaultLevelColors_BD(void)
+{
+  int i;
+
+  for (i = 0; i < MAX_BD_COLORS; i++)
+    bd_color_default[i] = *bd_color[i];
+}
+
+void SetRandomLevelColors_BD(int bd_color_type)
+{
+  struct LevelInfo_BD *level_bd = level.native_bd_level;
+  GdCave *cave = level_bd->cave;
+
+  // create random cave colors
+  gd_cave_set_random_colors(cave, bd_color_type);
+
+  // copy colors to level editor
+  level.bd_color_b = cave->colorb;
+  level.bd_color_0 = cave->color0;
+  level.bd_color_1 = cave->color1;
+  level.bd_color_2 = cave->color2;
+  level.bd_color_3 = cave->color3;
+  level.bd_color_4 = cave->color4;
+  level.bd_color_5 = cave->color5;
+}
+
+static void DrawColorBox_BD(int nr)
+{
+  int id = ED_SELECTBOX_ID_COLORS_FIRST + nr;
+  struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
+  int graphic = IMG_EDITOR_CHECKBOX;
+  struct GraphicInfo *gd = &graphic_info[graphic];
+  int offset = ED_GADGET_TEXT_DISTANCE;
+  int x1 = gi->x - offset - gd->width;
+  int y1 = gi->y;
+  int x2 = x1 + offset;
+  int y2 = y1 + offset;
+  int xsize1 = gd->width;
+  int ysize1 = gd->height;
+  int xsize2 = xsize1 - 2 * offset;
+  int ysize2 = ysize1 - 2 * offset;
+  int bd_color_x = *bd_color[nr];
+  int r = gd_color_get_r(bd_color_x);
+  int g = gd_color_get_g(bd_color_x);
+  int b = gd_color_get_b(bd_color_x);
+  Pixel color = SDL_MapRGB(drawto->surface->format, r, g, b);
+
+  BlitBitmap(gd->bitmap, drawto, gd->src_x, gd->src_y, xsize1, ysize1, x1, y1);
+  FillRectangle(drawto, x2, y2, xsize2, ysize2, color);
+}
+
+static void DrawEngineConfigColors(void)
+{
+  int i;
+
+  if (bd_color_type_changed)
+  {
+    if (level.bd_color_type != GD_COLOR_TYPE_RGB && level.bd_color_type != GetCommonColorType_BD())
+    {
+      // color type switched to non-RGB colors, but using different color type => reset colors
+
+      if (level.bd_color_type == bd_color_type_default)
+      {
+       // color type switched to same color type as default colors => reset to defaults
+       for (i = 0; i < MAX_BD_COLORS; i++)
+         *bd_color[i] = bd_color_default[i];
+      }
+      else
+      {
+       // color type switched to different color type as default colors => use random colors
+       SetRandomLevelColors_BD(level.bd_color_type);
+      }
+    }
+
+    bd_color_type_changed = FALSE;
+  }
+
+  // copy level colors to either C64-style color index or color text
+  for (i = 0; i < MAX_BD_COLORS; i++)
+  {
+    int bd_color_x = (level.bd_color_type == GD_COLOR_TYPE_C64 ? *bd_color[i] & 0x0f :
+                     level.bd_color_type == GD_COLOR_TYPE_RGB ? gd_color_get_rgb(*bd_color[i]) :
+                     *bd_color[i]);
+
+    if (level.bd_color_type == GD_COLOR_TYPE_C64)
+      bd_color_c64[i] = bd_color_x;
+    else
+      snprintf(bd_color_text[i], sizeof(bd_color_text[i]), "%s", gd_color_get_string(bd_color_x));
+  }
+
+  MapSelectboxGadget(ED_SELECTBOX_ID_BD_COLOR_TYPE);
+
+  if (level.bd_color_type == GD_COLOR_TYPE_C64)
+  {
+    // draw selectbox gadgets
+    for (i = ED_SELECTBOX_ID_COLORS_FIRST; i <= ED_SELECTBOX_ID_COLORS_LAST; i++)
+      MapSelectboxGadget(i);
+  }
+  else
+  {
+    // draw text input gadgets
+    for (i = ED_TEXTINPUT_ID_COLORS_FIRST; i <= ED_TEXTINPUT_ID_COLORS_LAST; i++)
+      MapTextInputGadget(i);
+  }
+
+  for (i = 0; i < MAX_BD_COLORS; i++)
+    DrawColorBox_BD(i);
+
+  MapTextbuttonGadget(ED_TEXTBUTTON_ID_BD_SET_RANDOM_COLORS);
+}
+
+static void DrawLevelConfigEngine(void)
+{
+  if (edit_mode_engineconfig == ED_MODE_ENGINECONFIG_CONFIG)
+    DrawEngineConfigConfig();
+  else if (edit_mode_engineconfig == ED_MODE_ENGINECONFIG_COLORS)
+    DrawEngineConfigColors();
+}
+
+static void DrawLevelConfigWindow(void)
 {
   char *text = "Global Settings";
   int font_nr = FONT_TITLE_1;
@@ -9290,6 +11525,11 @@ static void DrawLevelInfoWindow(void)
 
   stick_element_properties_window = FALSE;
 
+  // make sure that previous level config edit mode exists for this level
+  if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE &&
+      level.game_engine_type != GAME_ENGINE_TYPE_BD)
+    edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
+
   SetAutomaticNumberOfGemsNeeded();
 
   UnmapLevelEditorFieldGadgets();
@@ -9299,14 +11539,16 @@ static void DrawLevelInfoWindow(void)
 
   DrawText(sx, sy, text, font_nr);
 
-  DrawLevelInfoTabulatorGadgets();
+  DrawLevelConfigTabulatorGadgets();
 
-  if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL)
-    DrawLevelInfoLevel();
-  else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVELSET)
-    DrawLevelInfoLevelSet();
-  else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR)
-    DrawLevelInfoEditor();
+  if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
+    DrawLevelConfigLevel();
+  else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
+    DrawLevelConfigLevelSet();
+  else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
+    DrawLevelConfigEditor();
+  else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_ENGINE)
+    DrawLevelConfigEngine();
 }
 
 static void DrawCustomContentArea(void)
@@ -9421,7 +11663,7 @@ static void DrawMagicBallContentAreas(void)
   DrawText(x, y + 2 * tilesize, "active",    font_nr);
 }
 
-static void DrawAndroidElementArea(int element)
+static void DrawAndroidElementArea(void)
 {
   int id = ED_DRAWING_ID_ANDROID_CONTENT;
   int num_elements = level.num_android_clone_elements;
@@ -9449,7 +11691,7 @@ static void DrawAndroidElementArea(int element)
   MapDrawingArea(id);
 }
 
-static void DrawGroupElementArea(int element)
+static void DrawGroupElementArea(void)
 {
   int id = ED_DRAWING_ID_GROUP_CONTENT;
   int num_elements = group_element_info.num_elements;
@@ -9506,13 +11748,40 @@ static void DrawPlayerInitialInventoryArea(int element)
   MapDrawingArea(id);
 }
 
+static void DrawMMBallContentArea(void)
+{
+  int id = ED_DRAWING_ID_MM_BALL_CONTENT;
+  int num_elements = level.num_mm_ball_contents;
+  int border_size = ED_DRAWINGAREA_BORDER_SIZE;
+  int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
+  int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
+  int xsize = MAX_MM_BALL_CONTENTS;
+  int ysize = 1;
+
+  if (drawingarea_info[id].text_left != NULL)
+    sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+  UnmapDrawingArea(id);
+
+  ModifyEditorDrawingArea(id, num_elements, 1);
+
+  // delete content areas in case of reducing number of them
+  DrawBackground(sx, sy,
+                xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
+                ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
+
+  MapDrawingArea(id);
+}
+
 static void DrawEnvelopeTextArea(int envelope_nr)
 {
   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
 
   UnmapGadget(gi);
-  DrawBackground(gi->x, gi->y, gi->width, gi->height);
+
+  DrawBackground(gi->x, gi->y,
+                gi->textarea.crop_width, gi->textarea.crop_height);
 
   if (envelope_nr != -1)
     textarea_info[id].value = level.envelope[envelope_nr].text;
@@ -9586,13 +11855,16 @@ static void DrawPropertiesInfo(void)
     { -1,                      NULL                                    }
   };
   char *filename = getElementDescriptionFilename(properties_element);
-  char *percentage_text = "In this level: ";
+  char *num_elements_text = "In this level: ";
+  char *num_similar_text = "Similar tiles: ";
   char *properties_text = "Standard properties: ";
   char *description_text = "Description:";
   char *no_description_text = "No description available.";
   char *none_text = "None";
   float percentage;
-  int num_elements_in_level;
+  int num_elements_in_level = 0;
+  int num_similar_in_level = 0;
+  int num_hires_tiles_in_level = 0;
   int num_standard_properties = 0;
   int font1_nr = FONT_TEXT_1;
   int font2_nr = FONT_TEXT_2;
@@ -9601,7 +11873,8 @@ static void DrawPropertiesInfo(void)
   int font2_height = getFontHeight(font2_nr);
   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
   int font2_yoffset = (font1_height - font2_height) / 2;
-  int percentage_text_len = strlen(percentage_text) * font1_width;
+  int num_elements_text_len = strlen(num_elements_text) * font1_width;
+  int num_similar_text_len = strlen(num_similar_text) * font1_width;
   int properties_text_len = strlen(properties_text) * font1_width;
   int xpos = ED_ELEMENT_SETTINGS_X(0);
   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
@@ -9620,51 +11893,100 @@ static void DrawPropertiesInfo(void)
 
   // ----- print number of elements / percentage of this element in level
 
-  num_elements_in_level = 0;
-  for (y = 0; y < lev_fieldy; y++) 
+  for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
+    {
       if (Tile[x][y] == properties_element)
+      {
        num_elements_in_level++;
+      }
+      else if (IS_MM_WALL(Tile[x][y]) &&
+              map_mm_wall_element(Tile[x][y]) == properties_element)
+      {
+       num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
+      }
+    }
+  }
+
   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-  DrawTextS(xpos, ypos, font1_nr, percentage_text);
+  DrawTextS(xpos, ypos, font1_nr, num_elements_text);
 
-  if (num_elements_in_level > 0)
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+  if (num_hires_tiles_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
+             "%d wall tiles", num_hires_tiles_in_level);
+  else if (num_elements_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              "%d (%.2f %%)", num_elements_in_level, percentage);
   else
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              none_text);
 
-  ypos += 2 * MAX(font1_height, font2_height);
-
-  // ----- print standard properties of this element
+  // ----- print number of similar elements / percentage of them in level
 
-  DrawTextS(xpos, ypos, font1_nr, properties_text);
-
-  ypos += line1_height;
+  for (y = 0; y < lev_fieldy; y++)
+  {
+    for (x = 0; x < lev_fieldx; x++)
+    {
+      if (strEqual(element_info[Tile[x][y]].class_name,
+                  element_info[properties_element].class_name))
+      {
+       num_similar_in_level++;
+      }
+    }
+  }
 
-  for (i = 0; properties[i].value != -1; i++)
+  if (num_similar_in_level != num_elements_in_level)
   {
-    if (!HAS_PROPERTY(properties_element, properties[i].value))
-      continue;
+    ypos += 1 * MAX(font1_height, font2_height);
 
-    DrawTextS(xpos, ypos, font2_nr, properties[i].text);
+    percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-    ypos += font2_height;
+    DrawTextS(xpos, ypos, font1_nr, num_similar_text);
 
-    num_standard_properties++;
+    if (num_similar_in_level > 0)
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               "%d (%.2f %%)", num_similar_in_level, percentage);
+    else
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               none_text);
   }
 
-  if (num_standard_properties == 0)
+  ypos += 2 * MAX(font1_height, font2_height);
+
+  // ----- print standard properties of this element (only for certain game engines)
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_RND ||
+      level.game_engine_type == GAME_ENGINE_TYPE_EM ||
+      level.game_engine_type == GAME_ENGINE_TYPE_SP)
   {
-    DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
-             font2_nr, none_text);
+    DrawTextS(xpos, ypos, font1_nr, properties_text);
 
-    ypos -= (line1_height - font1_height);
-  }
+    ypos += line1_height;
+
+    for (i = 0; properties[i].value != -1; i++)
+    {
+      if (!HAS_PROPERTY(properties_element, properties[i].value))
+       continue;
+
+      DrawTextS(xpos, ypos, font2_nr, properties[i].text);
+
+      ypos += font2_height;
+
+      num_standard_properties++;
+    }
+
+    if (num_standard_properties == 0)
+    {
+      DrawTextS(xpos + properties_text_len, ypos - line1_height + font2_yoffset,
+               font2_nr, none_text);
+
+      ypos -= (line1_height - font1_height);
+    }
 
-  ypos += MAX(font1_height, font2_height);
+    ypos += MAX(font1_height, font2_height);
+  }
 
   // ----- print special description of this element
 
@@ -9676,176 +11998,278 @@ static void DrawPropertiesInfo(void)
     PrintInfoText(no_description_text, font1_nr, xpos, ypos - line1_height);
 }
 
-#define TEXT_COLLECTING                "Score for collecting"
-#define TEXT_SMASHING          "Score for smashing"
-#define TEXT_SLURPING          "Score for slurping robot"
-#define TEXT_CRACKING          "Score for cracking"
-#define TEXT_AMOEBA_SPEED      "Speed of amoeba growth"
-#define TEXT_DURATION          "Duration when activated"
-#define TEXT_DELAY_ON          "Delay before activating"
-#define TEXT_DELAY_OFF         "Delay before deactivating"
-#define TEXT_DELAY_EXPLODING   "Delay before exploding"
-#define TEXT_DELAY_MOVING      "Delay before moving"
-#define TEXT_BALL_DELAY                "Element generation delay"
-#define TEXT_MOVE_SPEED                "Speed of android moving"
-#define TEXT_CLONE_SPEED       "Speed of android cloning"
-#define TEXT_GAME_OF_LIFE_1    "Min neighbours to survive"
-#define TEXT_GAME_OF_LIFE_2    "Max neighbours to survive"
-#define TEXT_GAME_OF_LIFE_3    "Min neighbours to create"
-#define TEXT_GAME_OF_LIFE_4    "Max neighbours to create"
-#define TEXT_TIME_BONUS                "Extra time to solve level"
+#define TEXT_COLLECTING                        "Score for collecting"
+#define TEXT_COLLECTING_EXTRA          "Score for extra diamonds"
+#define TEXT_SMASHING                  "Score for smashing"
+#define TEXT_SLURPING                  "Score for slurping robot"
+#define TEXT_CRACKING                  "Score for cracking"
+#define TEXT_AMOEBA_SPEED              "Speed of amoeba growth"
+#define TEXT_AMOEBA_THRESHOED          "Size for turning to rocks"
+#define TEXT_AMOEBA_SLOW_TIME          "Slow growth time (seconds)"
+#define TEXT_AMOEBA_SLOW_RATE          "Slow growth rate (percent)"
+#define TEXT_AMOEBA_FAST_RATE          "Fast growth rate (percent)"
+#define TEXT_DURATION                  "Duration when activated"
+#define TEXT_DELAY_ON                  "Delay before activating"
+#define TEXT_DELAY_OFF                 "Delay before deactivating"
+#define TEXT_DELAY_CHANGING            "Delay before changing"
+#define TEXT_DELAY_EXPLODING           "Delay before exploding"
+#define TEXT_DELAY_MOVING              "Delay before moving"
+#define TEXT_BALL_DELAY                        "Element generation delay"
+#define TEXT_MOVE_SPEED                        "Speed of android moving"
+#define TEXT_CLONE_SPEED               "Speed of android cloning"
+#define TEXT_GAME_OF_LIFE_1            "Min neighbours to survive"
+#define TEXT_GAME_OF_LIFE_2            "Max neighbours to survive"
+#define TEXT_GAME_OF_LIFE_3            "Min neighbours to create"
+#define TEXT_GAME_OF_LIFE_4            "Max neighbours to create"
+#define TEXT_TIME_BONUS                        "Extra time to solve level"
+#define TEXT_TIME_PENALTY              "Time penalty if destroyed"
+#define TEXT_PERMEABILITY_RATE         "slime permeability rate"
+#define TEXT_PERMEABILITY_BITS         "slime permeability bits"
+#define TEXT_RANDOM_SEED               "slime random number seed"
+#define TEXT_ACID_SPREAD_RATE          "Spread rate (percent)"
+#define TEXT_BITER_MOVE_DELAY          "Move delay (BD frames)"
+#define TEXT_REPLICATION_DELAY         "Create delay (BD frames)"
+#define TEXT_HAMMER_BREAK_DELAY                "Delay for breaking walls"
+#define TEXT_HAMMER_REAPPEAR_DELAY     "Delay for reappearing walls"
+#define TEXT_SKELETONS_NEEDED          "Skeletons needed to use pot"
+#define TEXT_SKELETONS_WORTH           "Counts as this many diamonds"
+#define TEXT_AUTO_TURN_DELAY           "Creatures auto turn delay"
+#define TEXT_GRAVITY_DELAY             "Gravity switch change delay"
 
 static struct
 {
   int element;
   int *value;
   char *text;
+  int min_value;
+  int max_value;
 } elements_with_counter[] =
 {
-  { EL_EMERALD,                &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_BD_DIAMOND,     &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_EMERALD_YELLOW, &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_EMERALD_RED,    &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_EMERALD_PURPLE, &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_SP_INFOTRON,    &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_DIAMOND,                &level.score[SC_DIAMOND],       TEXT_COLLECTING },
-  { EL_CRYSTAL,                &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
-  { EL_PEARL,          &level.score[SC_PEARL],         TEXT_COLLECTING },
-  { EL_BUG,            &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BUG_RIGHT,      &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BUG_UP,         &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BUG_LEFT,       &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BUG_DOWN,       &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BD_BUTTERFLY,   &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],                TEXT_SMASHING   },
-  { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],                TEXT_SMASHING   },
-  { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],                TEXT_SMASHING   },
-  { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],                TEXT_SMASHING   },
-  { EL_SP_ELECTRON,    &level.score[SC_BUG],           TEXT_SMASHING   },
-  { EL_SPACESHIP,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_SPACESHIP_RIGHT,        &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_SPACESHIP_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_SPACESHIP_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_SPACESHIP_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_BD_FIREFLY,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],    TEXT_SMASHING   },
-  { EL_BD_FIREFLY_UP,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],    TEXT_SMASHING   },
-  { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],    TEXT_SMASHING   },
-  { EL_SP_SNIKSNAK,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
-  { EL_YAMYAM,         &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_YAMYAM_LEFT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_YAMYAM_RIGHT,   &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_YAMYAM_UP,      &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_YAMYAM_DOWN,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_DARK_YAMYAM,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
-  { EL_ROBOT,          &level.score[SC_ROBOT],         TEXT_SMASHING   },
-  { EL_PACMAN,         &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_PACMAN_RIGHT,   &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_PACMAN_UP,      &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_PACMAN_LEFT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_PACMAN_DOWN,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_NUT,            &level.score[SC_NUT],           TEXT_CRACKING   },
-  { EL_DYNAMITE,       &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
-  { EL_EM_DYNAMITE,    &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_SHIELD_NORMAL,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
-  { EL_SHIELD_DEADLY,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
-  { EL_EXTRA_TIME,     &level.extra_time_score,        TEXT_COLLECTING },
-  { EL_KEY_1,          &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_KEY_2,          &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_KEY_3,          &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_KEY_4,          &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EM_KEY_1,       &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EM_KEY_2,       &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EM_KEY_3,       &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EM_KEY_4,       &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EMC_KEY_5,      &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EMC_KEY_6,      &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EMC_KEY_7,      &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_EMC_KEY_8,      &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_DC_KEY_WHITE,   &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_MM_KETTLE,      &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_DF_CELL,                &level.score[SC_EMERALD],       TEXT_COLLECTING },
-  { EL_MM_KEY,         &level.score[SC_KEY],           TEXT_COLLECTING },
-  { EL_MM_LIGHTBALL,   &level.score[SC_ELEM_BONUS],    TEXT_COLLECTING },
-  { EL_MM_PACMAN,      &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_MM_PACMAN_RIGHT,        &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_MM_PACMAN_UP,   &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_MM_PACMAN_LEFT, &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_MM_PACMAN_DOWN, &level.score[SC_PACMAN],        TEXT_SMASHING   },
-  { EL_AMOEBA_WET,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
-  { EL_AMOEBA_DRY,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
-  { EL_AMOEBA_FULL,    &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
-  { EL_BD_AMOEBA,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
-  { EL_EMC_DRIPPER,    &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
-  { EL_MAGIC_WALL,     &level.time_magic_wall,         TEXT_DURATION   },
-  { EL_BD_MAGIC_WALL,  &level.time_magic_wall,         TEXT_DURATION   },
-  { EL_DC_MAGIC_WALL,  &level.time_magic_wall,         TEXT_DURATION   },
-  { EL_ROBOT_WHEEL,    &level.time_wheel,              TEXT_DURATION   },
-
-  { EL_TIMEGATE_SWITCH,          &level.time_timegate,         TEXT_DURATION   },
-  { EL_DC_TIMEGATE_SWITCH,&level.time_timegate,                TEXT_DURATION   },
-  { EL_LIGHT_SWITCH,   &level.time_light,              TEXT_DURATION   },
-  { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,         TEXT_DURATION   },
-  { EL_SHIELD_NORMAL,  &level.shield_normal_time,      TEXT_DURATION   },
-  { EL_SHIELD_DEADLY,  &level.shield_deadly_time,      TEXT_DURATION   },
-  { 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 },
-  { EL_GAME_OF_LIFE,   &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
-  { EL_GAME_OF_LIFE,   &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
-  { EL_GAME_OF_LIFE,   &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
-  { EL_BIOMAZE,                &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
-  { EL_BIOMAZE,                &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
-  { EL_BIOMAZE,                &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
-  { EL_BIOMAZE,                &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
-
-  { EL_EMC_ANDROID,    &level.android_move_time,       TEXT_MOVE_SPEED },
-  { EL_EMC_ANDROID,    &level.android_clone_time,      TEXT_CLONE_SPEED },
-  { EL_EMC_MAGIC_BALL, &level.ball_time,               TEXT_BALL_DELAY },
-  { EL_EMC_LENSES,     &level.lenses_score,            TEXT_COLLECTING },
-  { EL_EMC_MAGNIFIER,  &level.magnify_score,           TEXT_COLLECTING },
-  { EL_SPRING,         &level.slurp_score,             TEXT_SLURPING   },
-  { EL_SPRING_LEFT,    &level.slurp_score,             TEXT_SLURPING   },
-  { EL_SPRING_RIGHT,   &level.slurp_score,             TEXT_SLURPING   },
-  { EL_EMC_LENSES,     &level.lenses_time,             TEXT_DURATION   },
-  { EL_EMC_MAGNIFIER,  &level.magnify_time,            TEXT_DURATION   },
-  { EL_MM_FUSE_ACTIVE, &level.mm_time_fuse,            TEXT_DELAY_OFF  },
-  { EL_MM_BOMB,                &level.mm_time_bomb,            TEXT_DELAY_EXPLODING },
-  { EL_MM_GRAY_BALL,   &level.mm_time_ball,            TEXT_DELAY_ON   },
-  { EL_MM_STEEL_BLOCK, &level.mm_time_block,           TEXT_DELAY_MOVING },
-  { EL_MM_WOODEN_BLOCK,        &level.mm_time_block,           TEXT_DELAY_MOVING },
-
-  { -1,                        NULL,                           NULL            }
+  { EL_EMERALD,                        &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_BD_DIAMOND,             &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_BDX_DIAMOND,            &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_BDX_DIAMOND,            &level.score[SC_DIAMOND_EXTRA],         TEXT_COLLECTING_EXTRA   },
+  { EL_EMERALD_YELLOW,         &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_EMERALD_RED,            &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_EMERALD_PURPLE,         &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_SP_INFOTRON,            &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_DIAMOND,                        &level.score[SC_DIAMOND],               TEXT_COLLECTING         },
+  { EL_CRYSTAL,                        &level.score[SC_CRYSTAL],               TEXT_COLLECTING         },
+  { EL_PEARL,                  &level.score[SC_PEARL],                 TEXT_COLLECTING         },
+  { EL_BUG,                    &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BUG_RIGHT,              &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BUG_UP,                 &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BUG_LEFT,               &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BUG_DOWN,               &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BD_BUTTERFLY,           &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BD_BUTTERFLY_RIGHT,     &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BD_BUTTERFLY_UP,                &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BD_BUTTERFLY_LEFT,      &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_BD_BUTTERFLY_DOWN,      &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_SP_ELECTRON,            &level.score[SC_BUG],                   TEXT_SMASHING           },
+  { EL_SPACESHIP,              &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_SPACESHIP_RIGHT,                &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_SPACESHIP_UP,           &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_SPACESHIP_LEFT,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_SPACESHIP_DOWN,         &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_BD_FIREFLY,             &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_BD_FIREFLY_RIGHT,       &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_BD_FIREFLY_UP,          &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_BD_FIREFLY_LEFT,                &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_BD_FIREFLY_DOWN,                &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_SP_SNIKSNAK,            &level.score[SC_SPACESHIP],             TEXT_SMASHING           },
+  { EL_YAMYAM,                 &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_YAMYAM_LEFT,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_YAMYAM_RIGHT,           &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_YAMYAM_UP,              &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_YAMYAM_DOWN,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_DARK_YAMYAM,            &level.score[SC_YAMYAM],                TEXT_SMASHING           },
+  { EL_ROBOT,                  &level.score[SC_ROBOT],                 TEXT_SMASHING           },
+  { EL_PACMAN,                 &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_PACMAN_RIGHT,           &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_PACMAN_UP,              &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_PACMAN_LEFT,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_PACMAN_DOWN,            &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_NUT,                    &level.score[SC_NUT],                   TEXT_CRACKING           },
+  { EL_DYNAMITE,               &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
+  { EL_EM_DYNAMITE,            &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
+  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],             TEXT_COLLECTING         },
+  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
+  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE],              TEXT_COLLECTING         },
+  { EL_SHIELD_NORMAL,          &level.score[SC_SHIELD],                TEXT_COLLECTING         },
+  { EL_SHIELD_DEADLY,          &level.score[SC_SHIELD],                TEXT_COLLECTING         },
+  { EL_EXTRA_TIME,             &level.extra_time_score,                TEXT_COLLECTING         },
+  { EL_KEY_1,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_KEY_2,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_KEY_3,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_KEY_4,                  &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EM_KEY_1,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EM_KEY_2,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EM_KEY_3,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EM_KEY_4,               &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EMC_KEY_5,              &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EMC_KEY_6,              &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EMC_KEY_7,              &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_EMC_KEY_8,              &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_DC_KEY_WHITE,           &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_MM_KETTLE,              &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_DF_CELL,                        &level.score[SC_EMERALD],               TEXT_COLLECTING         },
+  { EL_MM_KEY,                 &level.score[SC_KEY],                   TEXT_COLLECTING         },
+  { EL_MM_LIGHTBALL,           &level.score[SC_ELEM_BONUS],            TEXT_COLLECTING         },
+  { EL_MM_PACMAN,              &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_MM_PACMAN_RIGHT,                &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_MM_PACMAN_UP,           &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_MM_PACMAN_LEFT,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_MM_PACMAN_DOWN,         &level.score[SC_PACMAN],                TEXT_SMASHING           },
+  { EL_AMOEBA_WET,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
+  { EL_AMOEBA_DRY,             &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
+  { EL_AMOEBA_FULL,            &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
+  { EL_BD_AMOEBA,              &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
+  { EL_EMC_DRIPPER,            &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
+  { EL_BDX_AMOEBA_1,           &level.bd_amoeba_1_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
+  { EL_BDX_AMOEBA_1,           &level.bd_amoeba_1_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
+  { EL_BDX_AMOEBA_1,           &level.bd_amoeba_1_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
+                               0, 100                                                          },
+  { EL_BDX_AMOEBA_1,           &level.bd_amoeba_1_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
+                               0, 100                                                          },
+  { EL_BDX_AMOEBA_2,           &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
+  { EL_BDX_AMOEBA_2,           &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
+  { EL_BDX_AMOEBA_2,           &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
+                               0, 100                                                          },
+  { EL_BDX_AMOEBA_2,           &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
+                               0, 100                                                          },
+  { EL_MAGIC_WALL,             &level.time_magic_wall,                 TEXT_DURATION           },
+  { EL_DC_MAGIC_WALL,          &level.time_magic_wall,                 TEXT_DURATION           },
+  { EL_BD_MAGIC_WALL,          &level.time_magic_wall,                 TEXT_DURATION           },
+  { EL_BDX_MAGIC_WALL,         &level.bd_magic_wall_time,              TEXT_DURATION           },
+  { EL_ROBOT_WHEEL,            &level.time_wheel,                      TEXT_DURATION           },
+  { EL_TIMEGATE_SWITCH,                &level.time_timegate,                   TEXT_DURATION           },
+  { EL_DC_TIMEGATE_SWITCH,     &level.time_timegate,                   TEXT_DURATION           },
+  { EL_LIGHT_SWITCH,           &level.time_light,                      TEXT_DURATION           },
+  { EL_LIGHT_SWITCH_ACTIVE,    &level.time_light,                      TEXT_DURATION           },
+  { EL_SHIELD_NORMAL,          &level.shield_normal_time,              TEXT_DURATION           },
+  { EL_SHIELD_DEADLY,          &level.shield_deadly_time,              TEXT_DURATION           },
+  { EL_BDX_CLOCK,              &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
+                               -100, 100                                                       },
+  { EL_BDX_VOODOO_DOLL,                &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
+                               0, 100                                                          },
+  { EL_BDX_SLIME,              &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
+                               0, 100                                                          },
+  { EL_BDX_SLIME,              &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
+                               0, 255                                                          },
+  { EL_BDX_SLIME,              &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
+                               -1, 65535                                                       },
+  { EL_BDX_ACID,               &level.bd_acid_spread_rate,             TEXT_ACID_SPREAD_RATE,
+                               0, 100                                                          },
+  { EL_BDX_BITER,              &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
+                               0, 3                                                            },
+  { EL_BDX_BITER_RIGHT,                &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
+                               0, 3                                                            },
+  { EL_BDX_BITER_UP,           &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
+                               0, 3                                                            },
+  { EL_BDX_BITER_LEFT,         &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
+                               0, 3                                                            },
+  { EL_BDX_BITER_DOWN,         &level.bd_biter_move_delay,             TEXT_BITER_MOVE_DELAY,
+                               0, 3                                                            },
+  { EL_BDX_REPLICATOR,         &level.bd_replicator_create_delay,      TEXT_REPLICATION_DELAY,
+                               0, 100                                                          },
+  { EL_BDX_PNEUMATIC_HAMMER,   &level.bd_hammer_walls_break_delay,     TEXT_HAMMER_BREAK_DELAY,
+                               1, 100                                                          },
+  { EL_BDX_PNEUMATIC_HAMMER,   &level.bd_hammer_walls_reappear_delay,  TEXT_HAMMER_REAPPEAR_DELAY,
+                               1, 200                                                          },
+  { EL_BDX_POT,                        &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
+                               0, 50                                                           },
+  { EL_BDX_SKELETON,           &level.bd_num_skeletons_needed_for_pot, TEXT_SKELETONS_NEEDED,
+                               0, 50                                                           },
+  { EL_BDX_SKELETON,           &level.bd_skeleton_worth_num_diamonds,  TEXT_SKELETONS_WORTH,
+                               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                                                           },
+  { 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_GAME_OF_LIFE,           &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
+  { EL_EMC_ANDROID,            &level.android_move_time,               TEXT_MOVE_SPEED         },
+  { EL_EMC_ANDROID,            &level.android_clone_time,              TEXT_CLONE_SPEED        },
+  { EL_EMC_MAGIC_BALL,         &level.ball_time,                       TEXT_BALL_DELAY         },
+  { EL_EMC_LENSES,             &level.lenses_score,                    TEXT_COLLECTING         },
+  { EL_EMC_MAGNIFIER,          &level.magnify_score,                   TEXT_COLLECTING         },
+  { EL_SPRING,                 &level.slurp_score,                     TEXT_SLURPING           },
+  { EL_SPRING_LEFT,            &level.slurp_score,                     TEXT_SLURPING           },
+  { EL_SPRING_RIGHT,           &level.slurp_score,                     TEXT_SLURPING           },
+  { EL_EMC_LENSES,             &level.lenses_time,                     TEXT_DURATION           },
+  { EL_EMC_MAGNIFIER,          &level.magnify_time,                    TEXT_DURATION           },
+  { EL_MM_FUSE_ACTIVE,         &level.mm_time_fuse,                    TEXT_DELAY_OFF          },
+  { EL_MM_BOMB,                        &level.mm_time_bomb,                    TEXT_DELAY_EXPLODING    },
+  { EL_MM_GRAY_BALL,           &level.mm_time_ball,                    TEXT_DELAY_CHANGING     },
+  { EL_MM_STEEL_BLOCK,         &level.mm_time_block,                   TEXT_DELAY_MOVING       },
+  { EL_MM_WOODEN_BLOCK,                &level.mm_time_block,                   TEXT_DELAY_MOVING       },
+
+  { -1,                                NULL,                                   NULL                    }
 };
 
 static boolean checkPropertiesConfig(int element)
 {
   int i;
 
+  // special case: empty space customization only available in R'n'D game engine
+  if (element == EL_EMPTY_SPACE && level.game_engine_type != GAME_ENGINE_TYPE_RND)
+    return FALSE;
+
   if (IS_GEM(element) ||
       IS_CUSTOM_ELEMENT(element) ||
       IS_GROUP_ELEMENT(element) ||
+      IS_EMPTY_ELEMENT(element) ||
       IS_BALLOON_ELEMENT(element) ||
       IS_ENVELOPE(element) ||
+      IS_MM_ENVELOPE(element) ||
       IS_MM_MCDUFFIN(element) ||
       IS_DF_LASER(element) ||
       IS_PLAYER_ELEMENT(element) ||
+      IS_BDX_PLAYER_ELEMENT(element) ||
+      IS_BD_FIREFLY(properties_element) ||
+      IS_BDX_FIREFLY_1(properties_element) ||
+      IS_BDX_FIREFLY_2(properties_element) ||
+      IS_BD_BUTTERFLY(properties_element) ||
+      IS_BDX_BUTTERFLY_1(properties_element) ||
+      IS_BDX_BUTTERFLY_2(properties_element) ||
+      IS_BDX_STONEFLY(properties_element) ||
+      IS_BDX_DRAGONFLY(properties_element) ||
+      IS_BDX_EXPANDABLE_WALL(properties_element) ||
+      IS_BDX_EXPANDABLE_STEELWALL(properties_element) ||
+      IS_BDX_CONVEYOR_BELT(properties_element) ||
+      IS_BDX_CONVEYOR_BELT_SWITCH(properties_element) ||
+      IS_SOKOBAN_OBJECT_OR_FIELD(element) ||
       HAS_EDITOR_CONTENT(element) ||
       CAN_GROW(element) ||
       COULD_MOVE_INTO_ACID(element) ||
       MAYBE_DONT_COLLIDE_WITH(element) ||
-      element == EL_SOKOBAN_OBJECT ||
-      element == EL_SOKOBAN_FIELD_EMPTY ||
-      element == EL_SOKOBAN_FIELD_FULL)
+      element == EL_BDX_SAND_1 ||
+      element == EL_BDX_ROCK ||
+      element == EL_BDX_MEGA_ROCK ||
+      element == EL_BDX_BOMB ||
+      element == EL_BDX_ROCKET_LAUNCHER ||
+      element == EL_BDX_NITRO_PACK ||
+      element == EL_BDX_SWEET ||
+      element == EL_BDX_VOODOO_DOLL ||
+      element == EL_BDX_WATER ||
+      element == EL_BDX_GRAVITY_SWITCH)
+  {
     return TRUE;
+  }
   else
+  {
     for (i = 0; elements_with_counter[i].element != -1; i++)
       if (elements_with_counter[i].element == element)
        return TRUE;
+  }
 
   return FALSE;
 }
@@ -9872,6 +12296,7 @@ static void SetAutomaticNumberOfGemsNeeded(void)
        case EL_EMERALD_RED:
        case EL_EMERALD_PURPLE:
        case EL_BD_DIAMOND:
+       case EL_BDX_DIAMOND:
        case EL_WALL_EMERALD:
        case EL_WALL_EMERALD_YELLOW:
        case EL_WALL_EMERALD_RED:
@@ -9920,8 +12345,7 @@ static void DrawPropertiesConfig(void)
     int xpos = ED_ELEMENT_SETTINGS_X(0);
     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
 
-    PrintInfoText("No configuration options available.",
-                 FONT_TEXT_1, xpos, ypos);
+    PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
 
     return;
   }
@@ -9929,41 +12353,65 @@ static void DrawPropertiesConfig(void)
   // check if there are elements where a value can be chosen for
   for (i = 0; elements_with_counter[i].element != -1; i++)
   {
-    if (elements_with_counter[i].element == properties_element)
-    {
-      int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
-
-      counterbutton_info[counter_id].y =
-       ED_ELEMENT_SETTINGS_YPOS(
-               (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
-               (CAN_GROW(properties_element)                ? 1 : 0) +
-               (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
-               (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
-               (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
-               num_element_counters);
-
-      counterbutton_info[counter_id].value = elements_with_counter[i].value;
-      counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
-
-      if (properties_element == EL_GAME_OF_LIFE ||
-         properties_element == EL_BIOMAZE)
-      {
-       counterbutton_info[counter_id].min_value = 0;   // min neighbours
-       counterbutton_info[counter_id].max_value = 8;   // max neighbours
-      }
-      else
-      {
-       // !!! CHANGE THIS FOR CERTAIN ELEMENTS !!!
-       counterbutton_info[counter_id].min_value = MIN_SCORE;
-       counterbutton_info[counter_id].max_value = MAX_SCORE;
-      }
+    if (elements_with_counter[i].element != properties_element)
+      continue;
 
-      MapCounterButtons(counter_id);
+    int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
+
+    counterbutton_info[counter_id].y =
+      ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)         ? 1 : 0) +
+                              (CAN_GROW(properties_element)                    ? 1 : 0) +
+                              (COULD_MOVE_INTO_ACID(properties_element)        ? 1 : 0) +
+                              (MAYBE_DONT_COLLIDE_WITH(properties_element)     ? 1 : 0) +
+                              (properties_element == EL_BDX_AMOEBA_1           ? 2 : 0) +
+                              (properties_element == EL_BDX_AMOEBA_2           ? 2 : 0) +
+                              (properties_element == EL_BDX_MAGIC_WALL         ? 1 : 0) +
+                              (properties_element == EL_BDX_VOODOO_DOLL        ? 4 : 0) +
+                              (properties_element == EL_BDX_SLIME              ? 1 : 0) +
+                              (properties_element == EL_BDX_ACID               ? 1 : 0) +
+                              (properties_element == EL_BDX_REPLICATOR         ? 1 : 0) +
+                              (properties_element == EL_BDX_CREATURE_SWITCH    ? 1 : 0) +
+                              (properties_element == EL_BDX_GRAVITY_SWITCH     ? 2 : 0) +
+                              (properties_element == EL_EMC_MAGIC_BALL         ? 2 : 0) +
+                              num_element_counters);
+
+    // special case: set position for delay counter for reappearing hammered walls
+    if (properties_element == EL_BDX_PNEUMATIC_HAMMER && num_element_counters > 0)
+      counterbutton_info[counter_id].y += 1;
+
+    counterbutton_info[counter_id].value      = elements_with_counter[i].value;
+    counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
+    counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
+    counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
+
+    // default: counter values between 0 and 999
+    if (counterbutton_info[counter_id].max_value == 0)
+      counterbutton_info[counter_id].max_value = 999;
+
+    MapCounterButtons(counter_id);
+
+    num_element_counters++;
+    if (num_element_counters >= max_num_element_counters)
+      break;
+  }
 
-      num_element_counters++;
-      if (num_element_counters >= max_num_element_counters)
-       break;
-    }
+  if (properties_element == EL_BDX_MAGIC_WALL)
+  {
+    // draw stickybutton gadget
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
+
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN);
+
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO);
+    MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO);
   }
 
   if (HAS_EDITOR_CONTENT(properties_element))
@@ -9971,14 +12419,50 @@ static void DrawPropertiesConfig(void)
     // draw stickybutton gadget
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
-    if (IS_AMOEBOID(properties_element))
+    if (properties_element == EL_BDX_AMOEBA_1)
+    {
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
+
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_TOO_BIG);
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_1_CONTENT_ENCLOSED);
+    }
+    else if (properties_element == EL_BDX_AMOEBA_2)
+    {
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA);
+
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG);
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_ENCLOSED);
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_EXPLODING);
+      MapDrawingArea(ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_LOOKS_LIKE);
+    }
+    else if (IS_AMOEBOID(properties_element))
+    {
       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
+    }
+    else if (properties_element == EL_BDX_ACID)
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_ACID_EATS_ELEMENT);
+      MapDrawingArea(ED_DRAWING_ID_BD_ACID_TURNS_TO_ELEMENT);
+    }
+    else if (IS_BDX_BITER(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_BITER_EATS_ELEMENT);
+    }
+    else if (properties_element == EL_BDX_BLADDER)
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_BLADDER_CONVERTS_BY_ELEMENT);
+    }
     else if (properties_element == EL_YAMYAM ||
             properties_element == EL_YAMYAM_LEFT ||
             properties_element == EL_YAMYAM_RIGHT ||
             properties_element == EL_YAMYAM_UP ||
             properties_element == EL_YAMYAM_DOWN)
+    {
       DrawYamYamContentAreas();
+    }
     else if (properties_element == EL_EMC_MAGIC_BALL)
     {
       DrawMagicBallContentAreas();
@@ -9986,8 +12470,19 @@ static void DrawPropertiesConfig(void)
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
     }
-    else if (properties_element == EL_EMC_ANDROID)
-      DrawAndroidElementArea(properties_element);
+    else if (properties_element == EL_EMC_ANDROID)
+    {
+      DrawAndroidElementArea();
+    }
+    else if (properties_element == EL_MM_GRAY_BALL)
+    {
+      MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
+      MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
+
+      DrawMMBallContentArea();
+    }
   }
 
   if (IS_PLAYER_ELEMENT(properties_element))
@@ -10063,13 +12558,190 @@ static void DrawPropertiesConfig(void)
     }
   }
 
-  if (IS_GEM(properties_element))
+  if (IS_BDX_PLAYER_ELEMENT(properties_element))
+  {
+    counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
+      ED_ELEMENT_SETTINGS_YPOS(2);
+    counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
+      ED_ELEMENT_SETTINGS_YPOS(3);
+    checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
+      ED_ELEMENT_SETTINGS_YPOS(4);
+
+    // draw checkbutton gadgets
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_DIAGONAL_MOVEMENTS);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_TOPMOST_PLAYER_ACTIVE);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
+
+    // draw counter gadgets
+    MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
+    MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
+
+    // draw drawing area gadgets
+    MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
+  }
+
+  if (properties_element == EL_BDX_SAND_1)
+  {
+    MapDrawingArea(ED_DRAWING_ID_BD_SAND_LOOKS_LIKE);
+  }
+
+  if (properties_element == EL_BDX_ROCK)
+  {
+    counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB].y =
+      ED_ELEMENT_SETTINGS_YPOS(0);
+    counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
+      ED_ELEMENT_SETTINGS_YPOS(1);
+
+    MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
+    MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
+
+    MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_FALLING);
+    MapDrawingArea(ED_DRAWING_ID_BD_ROCK_TURNS_TO_ON_IMPACT);
+  }
+
+  if (properties_element == EL_BDX_DIAMOND)
+  {
+    MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_FALLING);
+    MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_TURNS_TO_ON_IMPACT);
+  }
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    if (IS_BDX_FIREFLY_1(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_1_EXPLODES_TO);
+      MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
+    }
+    else if (IS_BDX_FIREFLY_2(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_FIREFLY_2_EXPLODES_TO);
+      MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
+    }
+    else if (IS_BDX_BUTTERFLY_1(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_1_EXPLODES_TO);
+      MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
+    }
+    else if (IS_BDX_BUTTERFLY_2(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_BUTTERFLY_2_EXPLODES_TO);
+      MapDrawingArea(ED_DRAWING_ID_BD_DIAMOND_BIRTH_TURNS_TO);
+    }
+    else if (IS_BDX_STONEFLY(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_STONEFLY_EXPLODES_TO);
+    }
+    else if (IS_BDX_DRAGONFLY(properties_element))
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_DRAGONFLY_EXPLODES_TO);
+      MapDrawingArea(ED_DRAWING_ID_BD_EXPLOSION_TURNS_TO);
+    }
+    else if (properties_element == EL_BDX_BOMB)
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_BOMB_EXPLOSION_TURNS_TO);
+    }
+    else if (properties_element == EL_BDX_NITRO_PACK)
+    {
+      MapDrawingArea(ED_DRAWING_ID_BD_NITRO_EXPLOSION_TURNS_TO);
+    }
+  }
+
+  if (properties_element == EL_BDX_MEGA_ROCK ||
+      properties_element == EL_BDX_SWEET)
+  {
+    counterbutton_info[ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET].y =
+      ED_ELEMENT_SETTINGS_YPOS(0);
+    checkbutton_info[ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET].y =
+      ED_ELEMENT_SETTINGS_YPOS(1);
+
+    MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
+  }
+
+  if (properties_element == EL_BDX_VOODOO_DOLL)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
+  }
+
+  if (properties_element == EL_BDX_SLIME)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
+
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_1);
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_1);
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_2);
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_2);
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_EATS_ELEMENT_3);
+    MapDrawingArea(ED_DRAWING_ID_BD_SLIME_CONVERTS_TO_ELEMENT_3);
+  }
+
+  if (IS_BDX_EXPANDABLE_WALL(properties_element) ||
+      IS_BDX_EXPANDABLE_STEELWALL(properties_element))
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CHANGE_EXPANDING_WALL);
+
+    if (IS_BDX_EXPANDABLE_WALL(properties_element))
+      MapDrawingArea(ED_DRAWING_ID_BD_EXPANDING_WALL_LOOKS_LIKE);
+  }
+
+  if (properties_element == EL_BDX_REPLICATOR)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_REPLICATORS_ACTIVE);
+  }
+
+  if (IS_BDX_CONVEYOR_BELT(properties_element) ||
+      IS_BDX_CONVEYOR_BELT_SWITCH(properties_element))
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_ACTIVE);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CONVEYOR_BELTS_CHANGED);
+  }
+
+  if (properties_element == EL_BDX_WATER)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_WATER_CANNOT_FLOW_DOWN);
+  }
+
+  if (properties_element == EL_BDX_PNEUMATIC_HAMMER)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_HAMMER_WALLS_REAPPEAR);
+  }
+
+  if (properties_element == EL_BDX_ROCKET_LAUNCHER)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_INFINITE_ROCKETS);
+  }
+
+  if (properties_element == EL_BDX_CREATURE_SWITCH)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_START_BACKWARDS);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_CREATURES_TURN_ON_HATCHING);
+  }
+
+  if (properties_element == EL_BDX_GRAVITY_SWITCH)
+  {
+    MapSelectboxGadget(ED_SELECTBOX_ID_BD_GRAVITY_DIRECTION);
+
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_SWITCH_ACTIVE);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_GRAVITY_AFFECTS_ALL);
+  }
+
+  if (properties_element == EL_BDX_NUT)
+  {
+    MapDrawingArea(ED_DRAWING_ID_BD_NUT_CONTENT);
+  }
+
+  // special case: slippery walls option for gems only available in R'n'D game engine
+  if (IS_GEM(properties_element) && level.game_engine_type == GAME_ENGINE_TYPE_RND)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
 
   if (properties_element == EL_EM_DYNAMITE)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
 
-  if (COULD_MOVE_INTO_ACID(properties_element) &&
+  if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
+      COULD_MOVE_INTO_ACID(properties_element) &&
       !IS_PLAYER_ELEMENT(properties_element) &&
       (!IS_CUSTOM_ELEMENT(properties_element) ||
        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
@@ -10100,7 +12772,7 @@ static void DrawPropertiesConfig(void)
       properties_element == EL_BIOMAZE)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_LIFE_BUGS);
 
-  if (CAN_GROW(properties_element))
+  if (CAN_GROW(properties_element) && level.game_engine_type != GAME_ENGINE_TYPE_BD)
   {
     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
       ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
@@ -10128,13 +12800,14 @@ static void DrawPropertiesConfig(void)
   if (IS_BALLOON_ELEMENT(properties_element))
     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
 
-  if (IS_ENVELOPE(properties_element))
+  if (IS_ENVELOPE(properties_element) ||
+      IS_MM_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
-    int envelope_nr = properties_element - EL_ENVELOPE_1;
+    int envelope_nr = ENVELOPE_NR(properties_element);
 
     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
@@ -10242,7 +12915,7 @@ static void DrawPropertiesConfig(void)
     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
 
     // draw drawing area gadgets
-    DrawGroupElementArea(properties_element);
+    DrawGroupElementArea();
 
     // draw text input gadgets
     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
@@ -10252,6 +12925,23 @@ static void DrawPropertiesConfig(void)
 
     draw_footer_line = TRUE;
   }
+  else if (IS_EMPTY_ELEMENT(properties_element))
+  {
+    // draw stickybutton gadget
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
+
+    // draw checkbutton gadgets
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
+
+    // draw textbutton gadgets
+    MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
+
+    // draw drawing area gadgets
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+
+    draw_footer_line = TRUE;
+  }
 
   // draw little footer border line above CE/GE use/save template gadgets
   if (draw_footer_line)
@@ -10326,13 +13016,25 @@ static void DrawPropertiesChange(void)
 
 static void DrawEditorElementAnimation(int x, int y)
 {
-  int graphic = el2img(properties_element);
-  int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
-              custom_element.ce_value_fixed_initial :
-              ANIM_MODE(graphic) == ANIM_CE_SCORE ?
-              custom_element.collect_score_initial : FrameCounter);
+  int graphic;
+  int frame;
+
+  if (IS_BDX_RUNTIME_ELEMENT(properties_element))
+  {
+    el2edimg_with_frame(properties_element, &graphic, &frame);
+
+    DrawFixedGraphicExt(drawto, x, y, graphic, frame);
+  }
+  else
+  {
+    graphic = el2img(properties_element);
+    frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
+            custom_element.ce_value_fixed_initial :
+            ANIM_MODE(graphic) == ANIM_CE_SCORE ?
+            custom_element.collect_score_initial : FrameCounter);
 
-  DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
+    DrawFixedGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
+  }
 }
 
 static void DrawEditorElementName(int x, int y, int font_nr)
@@ -10342,12 +13044,12 @@ static void DrawEditorElementName(int x, int y, int font_nr)
   int font_height = getFontHeight(font_nr);
   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
   int max_chars_per_line = max_text_width / font_width;
-  char buffer[max_chars_per_line + 1];
 
   if (strlen(element_name) <= max_chars_per_line)
     DrawTextS(x, y, font_nr, element_name);
   else
   {
+    char buffer[max_chars_per_line + 1];
     int next_pos = max_chars_per_line;
 
     strncpy(buffer, element_name, max_chars_per_line);
@@ -10423,9 +13125,7 @@ static void DrawPropertiesWindow(void)
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
-  if (IS_CUSTOM_ELEMENT(properties_element) ||
-      IS_GROUP_ELEMENT(properties_element))
-    MapLevelEditorToolboxCustomGadgets();
+  MapLevelEditorToolboxCustomGadgetsIfNeeded();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearField();
@@ -10734,13 +13434,7 @@ static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
 
 static int getClosedTube(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromTube(element_old);
   int direction_new = MV_NONE;
@@ -10748,8 +13442,8 @@ static int getClosedTube(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10764,13 +13458,7 @@ static int getClosedTube(int x, int y)
 
 static int getClosedBelt(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int nr = getBeltNrFromBeltElement(element_old);
   int direction_old = getOpenDirectionFromBelt(element_old);
@@ -10779,8 +13467,8 @@ static int getClosedBelt(int x, int y)
 
   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10795,13 +13483,7 @@ static int getClosedBelt(int x, int y)
 
 static int getClosedPool(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromPool(element_old);
   int direction_new = MV_NONE;
@@ -10809,8 +13491,8 @@ static int getClosedPool(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10826,13 +13508,7 @@ static int getClosedPool(int x, int y)
 
 static int getClosedPillar(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromPillar(element_old);
   int direction_new = MV_NONE;
@@ -10840,8 +13516,8 @@ static int getClosedPillar(int x, int y)
 
   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10856,13 +13532,7 @@ static int getClosedPillar(int x, int y)
 
 static int getClosedSteel2(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromSteel2(element_old);
   int direction_new = MV_NONE;
@@ -10870,8 +13540,8 @@ static int getClosedSteel2(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10886,13 +13556,7 @@ static int getClosedSteel2(int x, int y)
 
 static int getClosedChip(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromChip(element_old);
   int direction_new = MV_NONE;
@@ -10900,8 +13564,8 @@ static int getClosedChip(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10981,16 +13645,10 @@ static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
   SetElementSimple(x2, y2, *element2, change_level);
 }
 
-static void SetElementIntelliDraw(int x, int y, int new_element,
+static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
                                  boolean change_level, int button)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   static int last_x = -1;
   static int last_y = -1;
 
@@ -11016,8 +13674,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
@@ -11054,8 +13712,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_BELT(IntelliDrawBuffer[last_x][last_y]))
@@ -11092,8 +13750,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
@@ -11135,8 +13793,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
@@ -11172,8 +13830,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
@@ -11207,8 +13865,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
@@ -11268,8 +13926,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
@@ -11305,6 +13963,7 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
       { EL_EMERALD_PURPLE,             EL_WALL_EMERALD_PURPLE          },
       { EL_DIAMOND,                    EL_WALL_DIAMOND                 },
       { EL_BD_DIAMOND,                 EL_WALL_BD_DIAMOND              },
+      { EL_BDX_DIAMOND,                        EL_BDX_WALL_DIAMOND             },
       { EL_GATE_1,                     EL_GATE_1_GRAY                  },
       { EL_GATE_2,                     EL_GATE_2_GRAY                  },
       { EL_GATE_3,                     EL_GATE_3_GRAY                  },
@@ -11470,6 +14129,12 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_DF_RECEIVER_DOWN,
        EL_DF_RECEIVER_LEFT
       },
+      {
+       EL_DF_SLOPE_1,
+       EL_DF_SLOPE_4,
+       EL_DF_SLOPE_3,
+       EL_DF_SLOPE_2
+      },
 
       {
        -1,
@@ -11686,6 +14351,24 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_DF_MIRROR_ROTATING_3,
        EL_DF_MIRROR_ROTATING_2
       },
+      {
+       EL_DF_MIRROR_FIXED_1,
+       EL_DF_MIRROR_FIXED_16,
+       EL_DF_MIRROR_FIXED_15,
+       EL_DF_MIRROR_FIXED_14,
+       EL_DF_MIRROR_FIXED_13,
+       EL_DF_MIRROR_FIXED_12,
+       EL_DF_MIRROR_FIXED_11,
+       EL_DF_MIRROR_FIXED_10,
+       EL_DF_MIRROR_FIXED_9,
+       EL_DF_MIRROR_FIXED_8,
+       EL_DF_MIRROR_FIXED_7,
+       EL_DF_MIRROR_FIXED_6,
+       EL_DF_MIRROR_FIXED_5,
+       EL_DF_MIRROR_FIXED_4,
+       EL_DF_MIRROR_FIXED_3,
+       EL_DF_MIRROR_FIXED_2
+      },
 
       {
        -1,
@@ -11759,7 +14442,10 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
     }
   }
 
-  SetElementSimple(x, y, new_element, change_level);
+  if (IS_MM_WALL_EDITOR(new_element))
+    SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
+  else
+    SetElementSimple(x, y, new_element, change_level);
 
   last_x = x;
   last_y = y;
@@ -11773,7 +14459,7 @@ static void ResetIntelliDraw(void)
     for (y = 0; y < lev_fieldy; y++)
       IntelliDrawBuffer[x][y] = Tile[x][y];
 
-  SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
+  SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
 }
 
 static boolean draw_mode_hires = FALSE;
@@ -11788,6 +14474,14 @@ static boolean isHiresDrawElement(int element)
   return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
 }
 
+static int numHiresTiles(int element)
+{
+  if (IS_MM_WALL(element))
+    return get_number_of_bits(MM_WALL_BITS(element));
+
+  return 1;
+}
+
 static void SetDrawModeHiRes(int element)
 {
   draw_mode_hires =
@@ -11815,8 +14509,8 @@ static void SetElementExt(int x, int y, int dx, int dy, int element,
 {
   if (element < 0)
     SetElementSimple(x, y, Tile[x][y], change_level);
-  else if (GetKeyModState() & KMOD_Shift && !IS_MM_WALL_EDITOR(element))
-    SetElementIntelliDraw(x, y, element, change_level, button);
+  else if (GetKeyModState() & KMOD_Shift)
+    SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
   else
     SetElementSimpleExt(x, y, dx, dy, element, change_level);
 }
@@ -12018,7 +14712,7 @@ static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
-  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
+  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
 }
 #endif
 
@@ -12075,6 +14769,9 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
 #define CB_BRUSH_TO_CLIPBOARD          7
 #define CB_BRUSH_TO_CLIPBOARD_SMALL    8
 #define CB_UPDATE_BRUSH_POSITION       9
+#define CB_FLIP_BRUSH_X                        10
+#define CB_FLIP_BRUSH_Y                        11
+#define CB_FLIP_BRUSH_XY               12
 
 #define MAX_CB_PART_SIZE       10
 #define MAX_CB_LINE_SIZE       (MAX_LEV_FIELDX + 1)    // text plus newline
@@ -12083,6 +14780,185 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
                                 MAX_CB_NUM_LINES *     \
                                 MAX_CB_PART_SIZE)
 
+static int getFlippedTileExt(int map[], int element)
+{
+  int i;
+
+  for (i = 0; map[i] != -1; i++)
+    if (map[i] == element)
+      return map[i ^ 1];       // get flipped element by flipping LSB of index
+
+  return element;
+}
+
+static int getFlippedTileX(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_LEFT,              EL_BD_BUTTERFLY_RIGHT,
+    EL_BD_FIREFLY_LEFT,                        EL_BD_FIREFLY_RIGHT,
+    EL_BUG_LEFT,                       EL_BUG_RIGHT,
+    EL_SPACESHIP_LEFT,                 EL_SPACESHIP_RIGHT,
+    EL_PACMAN_LEFT,                    EL_PACMAN_RIGHT,
+    EL_ARROW_LEFT,                     EL_ARROW_RIGHT,
+    EL_MOLE_LEFT,                      EL_MOLE_RIGHT,
+    EL_BALLOON_SWITCH_LEFT,            EL_BALLOON_SWITCH_RIGHT,
+    EL_YAMYAM_LEFT,                    EL_YAMYAM_RIGHT,
+    EL_SP_PORT_LEFT,                   EL_SP_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_LEFT,           EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_LEFT,                EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,       EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_CONVEYOR_BELT_1_LEFT,           EL_CONVEYOR_BELT_1_RIGHT,
+    EL_CONVEYOR_BELT_2_LEFT,           EL_CONVEYOR_BELT_2_RIGHT,
+    EL_CONVEYOR_BELT_3_LEFT,           EL_CONVEYOR_BELT_3_RIGHT,
+    EL_CONVEYOR_BELT_4_LEFT,           EL_CONVEYOR_BELT_4_RIGHT,
+    EL_SPRING_LEFT,                    EL_SPRING_RIGHT,
+    EL_SP_CHIP_LEFT,                   EL_SP_CHIP_RIGHT,
+    EL_TUBE_VERTICAL_LEFT,             EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_LEFT_UP,                   EL_TUBE_RIGHT_UP,
+    EL_TUBE_LEFT_DOWN,                 EL_TUBE_RIGHT_DOWN,
+    EL_DC_STEELWALL_1_LEFT,            EL_DC_STEELWALL_1_RIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT,         EL_DC_STEELWALL_1_TOPRIGHT,
+    EL_DC_STEELWALL_1_BOTTOMLEFT,      EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,       EL_DC_STEELWALL_1_TOPRIGHT_2,
+    EL_DC_STEELWALL_1_BOTTOMLEFT_2,    EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_LEFT,            EL_DC_STEELWALL_2_RIGHT,
+    EL_ACID_POOL_TOPLEFT,              EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,           EL_ACID_POOL_BOTTOMRIGHT,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTileY(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_UP,                        EL_BD_BUTTERFLY_DOWN,
+    EL_BD_FIREFLY_UP,                  EL_BD_FIREFLY_DOWN,
+    EL_BUG_UP,                         EL_BUG_DOWN,
+    EL_SPACESHIP_UP,                   EL_SPACESHIP_DOWN,
+    EL_PACMAN_UP,                      EL_PACMAN_DOWN,
+    EL_ARROW_UP,                       EL_ARROW_DOWN,
+    EL_MOLE_UP,                                EL_MOLE_DOWN,
+    EL_BALLOON_SWITCH_UP,              EL_BALLOON_SWITCH_DOWN,
+    EL_YAMYAM_UP,                      EL_YAMYAM_DOWN,
+    EL_SP_PORT_UP,                     EL_SP_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_UP,             EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_UP,          EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_UP,         EL_SP_GRAVITY_OFF_PORT_DOWN,
+    EL_SP_CHIP_TOP,                    EL_SP_CHIP_BOTTOM,
+    EL_TUBE_HORIZONTAL_UP,             EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,                   EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,                  EL_TUBE_RIGHT_DOWN,
+    EL_DC_STEELWALL_1_TOP,             EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_TOPLEFT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT,                EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,      EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_TOP,             EL_DC_STEELWALL_2_BOTTOM,
+    EL_EMC_WALL_1,                     EL_EMC_WALL_3,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTileXY(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_LEFT,              EL_BD_BUTTERFLY_UP,
+    EL_BD_BUTTERFLY_RIGHT,             EL_BD_BUTTERFLY_DOWN,
+    EL_BD_FIREFLY_LEFT,                        EL_BD_FIREFLY_UP,
+    EL_BD_FIREFLY_RIGHT,               EL_BD_FIREFLY_DOWN,
+    EL_BUG_LEFT,                       EL_BUG_UP,
+    EL_BUG_RIGHT,                      EL_BUG_DOWN,
+    EL_SPACESHIP_LEFT,                 EL_SPACESHIP_UP,
+    EL_SPACESHIP_RIGHT,                        EL_SPACESHIP_DOWN,
+    EL_PACMAN_LEFT,                    EL_PACMAN_UP,
+    EL_PACMAN_RIGHT,                   EL_PACMAN_DOWN,
+    EL_ARROW_LEFT,                     EL_ARROW_UP,
+    EL_ARROW_RIGHT,                    EL_ARROW_DOWN,
+    EL_MOLE_LEFT,                      EL_MOLE_UP,
+    EL_MOLE_RIGHT,                     EL_MOLE_DOWN,
+    EL_BALLOON_SWITCH_LEFT,            EL_BALLOON_SWITCH_UP,
+    EL_BALLOON_SWITCH_RIGHT,           EL_BALLOON_SWITCH_DOWN,
+    EL_YAMYAM_LEFT,                    EL_YAMYAM_UP,
+    EL_YAMYAM_RIGHT,                   EL_YAMYAM_DOWN,
+    EL_SP_PORT_LEFT,                   EL_SP_PORT_UP,
+    EL_SP_PORT_RIGHT,                  EL_SP_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_LEFT,           EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_RIGHT,          EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,                EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,       EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,       EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,      EL_SP_GRAVITY_OFF_PORT_DOWN,
+    EL_SP_CHIP_LEFT,                   EL_SP_CHIP_TOP,
+    EL_SP_CHIP_RIGHT,                  EL_SP_CHIP_BOTTOM,
+    EL_TUBE_VERTICAL,                  EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,             EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_VERTICAL_RIGHT,            EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_DOWN,                 EL_TUBE_RIGHT_UP,
+    EL_DC_STEELWALL_1_LEFT,            EL_DC_STEELWALL_1_TOP,
+    EL_DC_STEELWALL_1_RIGHT,           EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_HORIZONTAL,      EL_DC_STEELWALL_1_VERTICAL,
+    EL_DC_STEELWALL_1_TOPRIGHT,                EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,      EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_2_LEFT,            EL_DC_STEELWALL_2_TOP,
+    EL_DC_STEELWALL_2_RIGHT,           EL_DC_STEELWALL_2_BOTTOM,
+    EL_DC_STEELWALL_2_HORIZONTAL,      EL_DC_STEELWALL_2_VERTICAL,
+    EL_EXPANDABLE_WALL_HORIZONTAL,     EL_EXPANDABLE_WALL_VERTICAL,
+    EL_EXPANDABLE_STEELWALL_HORIZONTAL,        EL_EXPANDABLE_STEELWALL_VERTICAL,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTile(int element, int mode)
+{
+  if (IS_MM_ELEMENT(element))
+  {
+    // get MM game element
+    element = map_element_RND_to_MM(element);
+
+    // get flipped game element
+    element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
+              mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
+              mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
+              element);
+
+    // get RND game element again
+    element = map_element_MM_to_RND(element);
+  }
+  else
+  {
+    // get flipped game element
+    element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
+              mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
+              mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
+              element);
+  }
+
+  return element;
+}
+
+static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
+{
+  // flip tiles
+  short tile1_flipped = getFlippedTile(*tile1, mode);
+  short tile2_flipped = getFlippedTile(*tile2, mode);
+
+  // swap tiles
+  *tile1 = tile2_flipped;
+  *tile2 = tile1_flipped;
+}
+
 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
 {
   DrawLineElement(sx, sy, element, change_level);
@@ -12311,6 +15187,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
       lev_fieldx = level.fieldx = brush_width;
       lev_fieldy = level.fieldy = brush_height;
 
+      boolean use_bd_engine = TRUE;
       boolean use_em_engine = TRUE;
       boolean use_sp_engine = TRUE;
       boolean use_mm_engine = TRUE;
@@ -12321,6 +15198,9 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        {
          int element = Tile[x][y];
 
+         if (!IS_BD_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
+           use_bd_engine = FALSE;
+
          if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
            use_em_engine = FALSE;
 
@@ -12332,7 +15212,8 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        }
       }
 
-      level.game_engine_type = (use_em_engine ? GAME_ENGINE_TYPE_EM :
+      level.game_engine_type = (use_bd_engine ? GAME_ENGINE_TYPE_BD :
+                               use_em_engine ? GAME_ENGINE_TYPE_EM :
                                use_sp_engine ? GAME_ENGINE_TYPE_SP :
                                use_mm_engine ? GAME_ENGINE_TYPE_MM :
                                GAME_ENGINE_TYPE_RND);
@@ -12443,6 +15324,37 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
     delete_old_brush = TRUE;
   }
+  else if (mode == CB_FLIP_BRUSH_X)
+  {
+    for (y = 0; y < brush_height; y++)
+      for (x = 0; x < (brush_width + 1) / 2; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[brush_width - x - 1][y], mode);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
+  else if (mode == CB_FLIP_BRUSH_Y)
+  {
+    for (y = 0; y < (brush_height + 1) / 2; y++)
+      for (x = 0; x < brush_width; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[x][brush_height - y - 1], mode);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
+  else if (mode == CB_FLIP_BRUSH_XY)
+  {
+    CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
+
+    for (y = 0; y < MAX(brush_width, brush_height); y++)
+      for (x = 0; x <= y; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[y][x], mode);
+
+    swap_numbers(&brush_width, &brush_height);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
 
   if (mode == CB_UPDATE_BRUSH_POSITION)
   {
@@ -12477,6 +15389,22 @@ static void DeleteBrushFromCursor(void)
   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
 }
 
+static void FlipBrushX(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
+}
+
+static void FlipBrushY(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
+}
+
+static void RotateBrush(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
+}
+
 void DumpBrush(void)
 {
   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
@@ -12554,7 +15482,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
   static int start_sx;
   static int last_sx, last_sy;
   static boolean typing = FALSE;
-  int letter_element = EL_CHAR_ASCII0 + letter;
+  int letter_element;
   int lx = 0, ly = 0;
 
   // map lower case letters to upper case and convert special characters
@@ -12805,7 +15733,8 @@ static void WrapLevel(int dx, int dy)
   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
 }
 
-static void DrawAreaElementHighlight(boolean highlighted)
+static void DrawAreaElementHighlight(boolean highlighted,
+                                    boolean highlighted_similar)
 {
   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
 
@@ -12818,26 +15747,69 @@ static void DrawAreaElementHighlight(boolean highlighted)
   {
     for (y = 0; y < ed_fieldy; y++)
     {
+      boolean highlight = FALSE;
       int lx = x + level_xpos;
       int ly = y + level_ypos;
 
       if (!IN_LEV_FIELD(lx, ly))
        continue;
 
-      if (Tile[lx][ly] != new_element1)
+      // check if element is the same
+      if (Tile[lx][ly] == new_element1)
+       highlight = TRUE;
+
+      // check if element is similar
+      if (highlighted_similar &&
+         strEqual(element_info[Tile[lx][ly]].class_name,
+                  element_info[new_element1].class_name))
+       highlight = TRUE;
+
+      // check if element is matching MM style wall
+      if (IS_MM_WALL(Tile[lx][ly]) &&
+         map_mm_wall_element(Tile[lx][ly]) == new_element1)
+       highlight = TRUE;
+
+      if (!highlight)
        continue;
 
-      int sx = SX + x * ed_tilesize;
-      int sy = SY + y * ed_tilesize;
-      int from_sx = sx;
-      int from_sy = sy;
-      int to_sx = sx + ed_tilesize - 1;
-      int to_sy = sy + ed_tilesize - 1;
-
-      DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
-      DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
-      DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
-      DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+      if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
+      {
+       int i;
+
+       for (i = 0; i < 4; i++)
+       {
+         if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
+           continue;
+
+         int xx = x * 2 + (i % 2);
+         int yy = y * 2 + (i / 2);
+         int sx = SX + xx * ed_tilesize / 2;
+         int sy = SY + yy * ed_tilesize / 2;
+         int from_sx = sx;
+         int from_sy = sy;
+         int to_sx = sx + ed_tilesize / 2 - 1;
+         int to_sy = sy + ed_tilesize / 2 - 1;
+
+         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
+         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
+         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
+         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+       }
+      }
+      else
+      {
+       int sx = SX + x * ed_tilesize;
+       int sy = SY + y * ed_tilesize;
+       int from_sx = sx;
+       int from_sy = sy;
+       int to_sx = sx + ed_tilesize - 1;
+       int to_sy = sy + ed_tilesize - 1;
+
+       DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
+       DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
+       DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
+       DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+      }
     }
   }
 }
@@ -12857,8 +15829,10 @@ static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
 static void HandleDrawingAreas(struct GadgetInfo *gi)
 {
   static boolean started_inside_drawing_area = FALSE;
-  static int last_sx = -1, last_sy = -1;
-  static int last_sx2 = -1, last_sy2 = -1;
+  static int last_sx = -1;
+  static int last_sy = -1;
+  static int last_sx2 = -1;
+  static int last_sy2 = -1;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   boolean button_press_event;
@@ -12878,8 +15852,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   int dx = sx2 % 2;
   int dy = sy2 % 2;
   int lx = 0, ly = 0;
-  int min_lx = 0, min_ly = 0;
-  int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
   int x, y;
 
   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
@@ -12891,6 +15863,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
   if (draw_level)
   {
+    int min_lx = 0, min_ly = 0;
+    int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
+
     // get positions inside level field
     lx = sx + level_xpos;
     ly = sy + level_ypos;
@@ -12919,14 +15894,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     sy2 = sy * 2 + dy;
   }
 
-  if (button_release_event)
-  {
-    last_sx = -1;
-    last_sy = -1;
-    last_sx2 = -1;
-    last_sy2 = -1;
-  }
-  else if (!button_press_event)
+  if (!button_press_event && !button_release_event)
   {
     int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
     boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
@@ -12953,9 +15921,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   if (!IS_VALID_BUTTON(button))
     return;
 
-  if (!button && !button_release_event)
-    return;
-
   // handle info callback for each invocation of action callback
   gi->callback_info(gi);
 
@@ -12991,10 +15956,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
              !inside_drawing_area)
            DeleteBrushFromCursor();
-       }
 
-       if (!button || button_release_event)
          break;
+       }
 
        if (draw_with_brush)
        {
@@ -13004,7 +15968,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          SetDrawModeHiRes(new_element);
 
-         if (IS_PLAYER_ELEMENT(new_element))
+         if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
          {
            // remove player at old position
            for (y = 0; y < lev_fieldy; y++)
@@ -13013,7 +15977,8 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
              {
                int old_element = Tile[x][y];
 
-               if (IS_PLAYER_ELEMENT(old_element))
+               if (IS_PLAYER_ELEMENT(old_element) &&
+                   IS_PLAYER_ELEMENT(new_element))
                {
                  int replaced_with_element =
                    (old_element == EL_SOKOBAN_FIELD_PLAYER &&
@@ -13033,6 +15998,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
                  SetElement(x, y, replaced_with_element);
                }
+               else if (IS_MM_MCDUFFIN(old_element) &&
+                        IS_MM_MCDUFFIN(new_element))
+               {
+                 // remove McDuffin at old position
+                 SetElement(x, y, EL_EMPTY);
+               }
              }
            }
          }
@@ -13079,22 +16050,19 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        if (button_release_event)
          CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 
-       if (button)
-       {
-         SetDrawModeHiRes(new_element);
+       SetDrawModeHiRes(new_element);
 
-         if (getDrawModeHiRes())
-         {
-           sx = sx2;
-           sy = sy2;
-         }
+       if (getDrawModeHiRes())
+       {
+         sx = sx2;
+         sy = sy2;
+       }
 
-         if (!button_press_event)
-           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
+       if (!button_press_event)
+         DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
 
-         last_sx = sx;
-         last_sy = sy;
-       }
+       last_sx = sx;
+       last_sy = sy;
       }
       break;
 
@@ -13277,11 +16245,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       break;
 
     case ED_COUNTER_ID_ANDROID_CONTENT:
-      DrawAndroidElementArea(properties_element);
+      DrawAndroidElementArea();
       break;
 
     case ED_COUNTER_ID_GROUP_CONTENT:
-      DrawGroupElementArea(properties_element);
+      DrawGroupElementArea();
       CopyGroupElementPropertiesToGame(properties_element);
       break;
 
@@ -13289,6 +16257,10 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawPlayerInitialInventoryArea(properties_element);
       break;
 
+    case ED_COUNTER_ID_MM_BALL_CONTENT:
+      DrawMMBallContentArea();
+      break;
+
     case ED_COUNTER_ID_ENVELOPE_XSIZE:
     case ED_COUNTER_ID_ENVELOPE_YSIZE:
       DrawEnvelopeTextArea(-1);
@@ -13336,6 +16308,15 @@ static void HandleTextInputGadgets(struct GadgetInfo *gi)
 
     ModifyEditorElementList(); // update changed button info text
   }
+  else if (type_id >= ED_TEXTINPUT_ID_COLORS_FIRST &&
+          type_id <= ED_TEXTINPUT_ID_COLORS_LAST)
+  {
+    int pos = type_id - ED_TEXTINPUT_ID_COLORS_FIRST;
+
+    *bd_color[pos] = gd_color_get_from_string(bd_color_text[pos]);
+
+    DrawColorBox_BD(pos);
+  }
 
   // do not mark level as modified for certain non-level-changing gadgets
   if (type_id >= ED_TEXTINPUT_ID_LEVELSET_FIRST &&
@@ -13366,7 +16347,7 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 
   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
   {
-    DrawLevelInfoWindow();
+    DrawLevelConfigWindow();
   }
   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
   {
@@ -13393,10 +16374,49 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
   }
   else if (type_id == ED_SELECTBOX_ID_GAME_ENGINE_TYPE)
   {
-    // update element selection list
+    // show or hide "engine" tabulator depending on game engine type
+    DrawLevelConfigWindow();
+
+    // update element selection list depending on game engine type
     ReinitializeElementList();
     ModifyEditorElementList();
   }
+  else if (type_id == ED_SELECTBOX_ID_BD_SCHEDULING_TYPE)
+  {
+    // update BD cycle delay counter gadgets depending on BD scheduling type
+    DrawLevelConfigWindow();
+  }
+  else if (type_id == ED_SELECTBOX_ID_BD_COLOR_TYPE)
+  {
+    bd_color_type_changed = TRUE;
+
+    if (level.bd_color_type != GD_COLOR_TYPE_RGB && level.bd_color_type != GetCommonColorType_BD())
+    {
+      // color type switched to non-RGB colors, but using different color type => reset colors
+      char *message = (level.bd_color_type == bd_color_type_default ?
+                      "This will reset colors to defaults! Continue?" :
+                      "This will reset colors to random colors! Continue?");
+
+      if (!Request(message, REQ_ASK))
+      {
+       // keep current RGB colors
+       level.bd_color_type = GD_COLOR_TYPE_RGB;
+       bd_color_type_changed = FALSE;
+      }
+    }
+
+    // update BD color palette gadgets depending on BD color type
+    DrawLevelConfigWindow();
+  }
+  else if (type_id >= ED_SELECTBOX_ID_COLORS_FIRST &&
+          type_id <= ED_SELECTBOX_ID_COLORS_LAST)
+  {
+    int pos = type_id - ED_SELECTBOX_ID_COLORS_FIRST;
+
+    *bd_color[pos] = gd_c64_color(bd_color_c64[pos]);
+
+    DrawColorBox_BD(pos);
+  }
 
   // do not mark level as modified for certain non-level-changing gadgets
   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE ||
@@ -13411,12 +16431,19 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
   int type_id = gi->custom_type_id;
   int i;
 
-  if (type_id >= ED_TAB_BUTTON_ID_LEVELINFO_FIRST &&
-      type_id <= ED_TAB_BUTTON_ID_LEVELINFO_LAST)
+  if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
+      type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
+  {
+    edit_mode_levelconfig = gi->custom_type_id;
+
+    DrawLevelConfigWindow();
+  }
+  else if (type_id >= ED_TAB_BUTTON_ID_ENGINECONFIG_FIRST &&
+          type_id <= ED_TAB_BUTTON_ID_ENGINECONFIG_LAST)
   {
-    edit_mode_levelinfo = gi->custom_type_id;
+    edit_mode_engineconfig = gi->custom_type_id;
 
-    DrawLevelInfoWindow();
+    DrawLevelConfigWindow();
   }
   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
           type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
@@ -13552,6 +16579,13 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
 
     level.changed = TRUE;
   }
+  else if (type_id == ED_TEXTBUTTON_ID_BD_SET_RANDOM_COLORS)
+  {
+    SetRandomLevelColors_BD(level.bd_color_type);
+
+    // update BD color palette gadgets after setting random colors
+    DrawLevelConfigWindow();
+  }
 }
 
 static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
@@ -13644,9 +16678,11 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
     boolean template_related_changes_found = FALSE;
     int i;
 
-    // check if any custom or group elements have been changed
+    // check if any custom, group or empty elements have been changed
     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-      if ((IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)) &&
+      if ((IS_CUSTOM_ELEMENT(i) ||
+          IS_GROUP_ELEMENT(i) ||
+          IS_EMPTY_ELEMENT(i)) &&
          element_info[i].modified_settings)
        template_related_changes_found = TRUE;
 
@@ -14070,12 +17106,12 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       break;
 
-    case GADGET_ID_INFO:
-      if (edit_mode != ED_MODE_INFO)
+    case GADGET_ID_CONF:
+      if (edit_mode != ED_MODE_LEVELCONFIG)
       {
        last_edit_mode = edit_mode;
 
-       ChangeEditModeWindow(ED_MODE_INFO);
+       ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
       }
       else
       {
@@ -14116,7 +17152,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          Request("Save this level and kill the old?", REQ_ASK))
       {
        if (leveldir_former->readonly)
-         ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
+         ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
 
        SetAutomaticNumberOfGemsNeeded();
 
@@ -14181,7 +17217,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          id <= GADGET_ID_ELEMENTLIST_LAST)
       {
        int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
-       int new_element = editor_elements[element_position + element_shift];
+
+       new_element = editor_elements[element_position + element_shift];
 
        if (IS_EDITOR_CASCADE(new_element))
        {
@@ -14189,8 +17226,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
          for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
          {
-           int *cascade_element= &(*editor_elements_info[i].headline_list)[0];
-           boolean *cascade_value=editor_elements_info[i].setup_cascade_value;
+           int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
+           boolean *cascade_value = editor_elements_info[i].setup_cascade_value;
 
            if (*cascade_element == new_element)
            {
@@ -14371,8 +17408,8 @@ void HandleLevelEditorKeyInput(Key key)
     case KSYM_Escape:
       if (edit_mode == ED_MODE_DRAWING)
        RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
-      else if (edit_mode == ED_MODE_INFO)
-       HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
+      else if (edit_mode == ED_MODE_LEVELCONFIG)
+       HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
       else if (edit_mode == ED_MODE_PROPERTIES)
        HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
       else if (edit_mode == ED_MODE_PALETTE)
@@ -14414,6 +17451,16 @@ void HandleLevelEditorKeyInput(Key key)
       if (letter && letter == controlbutton_info[i].shortcut)
        if (!anyTextGadgetActive())
          ClickOnGadget(level_editor_gadget[i], button);
+
+  if (draw_with_brush)
+  {
+    if (letter == 'x')
+      FlipBrushX();
+    else if (letter == 'y')
+      FlipBrushY();
+    else if (letter == 'z')
+      RotateBrush();
+  }
 }
 
 static void HandleLevelEditorIdle_Properties(void)
@@ -14421,11 +17468,12 @@ static void HandleLevelEditorIdle_Properties(void)
   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
   int x = editor.settings.element_graphic.x + element_border;
   int y = editor.settings.element_graphic.y + element_border;
-  static unsigned int action_delay = 0;
-  unsigned int action_delay_value = GameFrameDelay;
+  static DelayCounter action_delay = { 0 };
   int i;
 
-  if (!DelayReached(&action_delay, action_delay_value))
+  action_delay.value = GameFrameDelay;
+
+  if (!DelayReached(&action_delay))
     return;
 
   for (i = 0; i < ED_NUM_SELECTBOX; i++)
@@ -14446,16 +17494,20 @@ static void HandleLevelEditorIdle_Properties(void)
 static void HandleLevelEditorIdle_Drawing(void)
 {
   static boolean last_highlighted = FALSE;
+  static boolean last_highlighted_similar = FALSE;
   boolean highlighted = (GetKeyModState() & KMOD_Alt);
+  boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
 
-  if (highlighted != last_highlighted)
+  if (highlighted != last_highlighted ||
+      (highlighted && highlighted_similar != last_highlighted_similar))
   {
-    DrawAreaElementHighlight(highlighted);
-
-    last_highlighted = highlighted;
+    DrawAreaElementHighlight(highlighted, highlighted_similar);
 
     redraw_mask |= REDRAW_FIELD;
   }
+
+  last_highlighted = highlighted;
+  last_highlighted_similar = highlighted_similar;
 }
 
 void HandleLevelEditorIdle(void)
@@ -14474,7 +17526,6 @@ static void ClearEditorGadgetInfoText(void)
 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 {
   char infotext[MAX_OUTPUT_LINESIZE + 1];
-  char shortcut[MAX_OUTPUT_LINESIZE + 1];
   int max_infotext_len = getMaxInfoTextLength();
 
   if (gi == NULL || strlen(gi->info_text) == 0)
@@ -14489,6 +17540,8 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 
     if (key)
     {
+      char shortcut[MAX_OUTPUT_LINESIZE + 1];
+
       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
        sprintf(shortcut, " ('.' or '%c')", key);
       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
@@ -14532,7 +17585,6 @@ void HandleEditorGadgetInfoText(void *ptr)
 
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
-  static int start_lx, start_ly;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   int sx = gi->event.x;
@@ -14545,7 +17597,6 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   int actual_drawing_function = drawing_function;
   int max_infotext_len = getMaxInfoTextLength();
   char infotext[MAX_OUTPUT_LINESIZE + 1];
-  char *text;
 
   infotext[0] = '\0';          // start with empty info text
 
@@ -14582,10 +17633,14 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
       sy = ly - level_ypos;
     }
 
-    if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
+    if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
     {
       if (button_status)       // if (gi->state == GD_BUTTON_PRESSED)
       {
+       static int start_lx = 0;
+       static int start_ly = 0;
+       char *text;
+
        if (gi->event.type == GD_EVENT_PRESSED)
        {
          start_lx = lx;
@@ -14716,7 +17771,7 @@ void RequestExitLevelEditor(boolean ask_if_level_has_changed,
        vp_door_2->height == VYSIZE)
       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
     else
-      SetDoorState(DOOR_CLOSE_2);
+      SetDoorState(DOOR_CLOSE_ALL);
 
     BackToFront();
 
index 7270b202c048ef2a02f9987beceb03a8d65aa3d8..96fe6f29140077275d67e987c617f390216b2111 100644 (file)
@@ -14,6 +14,8 @@
 
 #include "main.h"
 
+boolean isLevelEditorTestGame(void);
+
 void CreateLevelEditorGadgets(void);
 void FreeLevelEditorGadgets(void);
 void UnmapLevelEditorGadgets(void);
@@ -34,4 +36,8 @@ void CopyBrushToClipboard_Small(void);
 void UndoLevelEditorOperation(void);
 void RedoLevelEditorOperation(void);
 
+void SetDefaultLevelColorType_BD(void);
+void SetDefaultLevelColors_BD(void);
+void SetRandomLevelColors_BD(int);
+
 #endif
diff --git a/src/engines.h b/src/engines.h
deleted file mode 100644 (file)
index 4e09b72..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// ============================================================================
-// Rocks'n'Diamonds - McDuffin Strikes Back!
-// ----------------------------------------------------------------------------
-// (c) 1995-2014 by Artsoft Entertainment
-//                         Holger Schemel
-//                 info@artsoft.org
-//                 https://www.artsoft.org/
-// ----------------------------------------------------------------------------
-// engines.h
-// ============================================================================
-
-#ifndef ENGINES_H
-#define ENGINES_H
-
-#include "libgame/libgame.h"
-
-#include "game_em/export.h"
-#include "game_sp/export.h"
-#include "game_mm/export.h"
-
-#include "game.h"
-
-
-// ============================================================================
-// functions and definitions exported from main program to game_em
-// ============================================================================
-
-void UpdateEngineValues(int, int, int, int);
-
-boolean swapTiles_EM(boolean);
-boolean getTeamMode_EM(void);
-boolean isActivePlayer_EM(int);
-
-int getScreenFieldSizeX(void);
-int getScreenFieldSizeY(void);
-
-void PlayLevelSound_EM(int, int, int, int);
-void InitGraphicInfo_EM(void);
-boolean CheckSingleStepMode_EM(byte action[], int, boolean, boolean, boolean);
-
-void SetGfxAnimation_EM(struct GraphicInfo_EM *, int, int, int, int);
-void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *, int, int, int, int);
-void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *, int, int, int);
-
-
-// ============================================================================
-// functions and definitions exported from main program to game_sp
-// ============================================================================
-
-void CheckSingleStepMode_SP(boolean, boolean);
-
-void getGraphicSource_SP(struct GraphicInfo_SP *, int, int, int, int);
-int getGraphicInfo_Delay(int);
-boolean isNextAnimationFrame_SP(int, int);
-
-
-// ============================================================================
-// functions and definitions exported from main program to game_mm
-// ============================================================================
-
-void SetDrawtoField(int);
-
-int el2img_mm(int);
-
-void CheckSingleStepMode_MM(boolean, boolean);
-
-int getGraphicAnimationFrame(int, int);
-void getGraphicSource(int, int, Bitmap **, int *, int *);
-void getMiniGraphicSource(int, Bitmap **, int *, int *);
-void getSizedGraphicSource(int, int, int, Bitmap **, int *, int *);
-
-
-#endif // ENGINES_H
index 13723bfa514da9ff8f78e499946907ad7d4729bd..04f69108527feaca46f5eca02ce2fc30b82f3ad9 100644 (file)
 
 static boolean cursor_inside_playfield = FALSE;
 static int cursor_mode_last = CURSOR_DEFAULT;
-static unsigned int special_cursor_delay = 0;
-static unsigned int special_cursor_delay_value = 1000;
+static DelayCounter special_cursor_delay = { 1000 };
+static boolean special_cursor_enabled = FALSE;
 
 static boolean stop_processing_events = FALSE;
+static boolean is_global_anim_event = FALSE;
 
 
 // forward declarations for internal use
@@ -48,6 +49,11 @@ static void HandleNoEvent(void);
 static void HandleEventActions(void);
 
 
+void SetPlayfieldMouseCursorEnabled(boolean enabled)
+{
+  special_cursor_enabled = enabled;
+}
+
 // event filter to set mouse x/y position (for pointer class global animations)
 // (this is especially required to ensure smooth global animation mouse pointer
 // movement when the screen is updated without handling events; this can happen
@@ -205,8 +211,7 @@ void StopProcessingEvents(void)
 static void HandleEvents(void)
 {
   Event event;
-  unsigned int event_frame_delay = 0;
-  unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
+  DelayCounter event_frame_delay = { GAME_FRAME_DELAY };
 
   ResetDelayCounter(&event_frame_delay);
 
@@ -271,7 +276,7 @@ static void HandleEvents(void)
       ResetDelayCounter(&event_frame_delay);
 
     // do not handle events for longer than standard frame delay period
-    if (DelayReached(&event_frame_delay, event_frame_delay_value))
+    if (DelayReached(&event_frame_delay))
       break;
 
     // do not handle any further events if triggered by a special flag
@@ -324,7 +329,7 @@ static void HandleMouseCursor(void)
     // when showing title screens, hide mouse pointer (if not moved)
 
     if (gfx.cursor_mode != CURSOR_NONE &&
-       DelayReached(&special_cursor_delay, special_cursor_delay_value))
+       DelayReached(&special_cursor_delay))
     {
       SetMouseCursor(CURSOR_NONE);
     }
@@ -340,11 +345,10 @@ static void HandleMouseCursor(void)
 
     if (gfx.cursor_mode != CURSOR_PLAYFIELD &&
        cursor_inside_playfield &&
-       DelayReached(&special_cursor_delay, special_cursor_delay_value))
+       special_cursor_enabled &&
+       DelayReached(&special_cursor_delay))
     {
-      if (level.game_engine_type != GAME_ENGINE_TYPE_MM ||
-         tile_cursor.enabled)
-       SetMouseCursor(CURSOR_PLAYFIELD);
+      SetMouseCursor(CURSOR_PLAYFIELD);
     }
   }
   else if (gfx.cursor_mode != CURSOR_DEFAULT)
@@ -524,6 +528,10 @@ void HandleButtonEvent(ButtonEvent *event)
   // for any mouse button event, disable playfield tile cursor
   SetTileCursorEnabled(FALSE);
 
+  // for any mouse button event, disable playfield mouse cursor
+  if (cursor_inside_playfield)
+    SetPlayfieldMouseCursorEnabled(FALSE);
+
 #if defined(HAS_SCREEN_KEYBOARD)
   if (video.shifted_up)
     event->y += video.shifted_up_pos;
@@ -576,7 +584,7 @@ void HandleWheelEvent(WheelEvent *event)
               event->y < 0 ? MB_WHEEL_DOWN :
               event->y > 0 ? MB_WHEEL_UP : 0);
 
-#if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_MAC)
   // accelerated mouse wheel available on Mac and Windows
   wheel_steps = (event->x ? ABS(event->x) : ABS(event->y));
 #else
@@ -613,6 +621,8 @@ void HandleWindowEvent(WindowEvent *event)
      subtype == SDL_WINDOWEVENT_FOCUS_GAINED ? "SDL_WINDOWEVENT_FOCUS_GAINED" :
      subtype == SDL_WINDOWEVENT_FOCUS_LOST ? "SDL_WINDOWEVENT_FOCUS_LOST" :
      subtype == SDL_WINDOWEVENT_CLOSE ? "SDL_WINDOWEVENT_CLOSE" :
+     subtype == SDL_WINDOWEVENT_TAKE_FOCUS ? "SDL_WINDOWEVENT_TAKE_FOCUS" :
+     subtype == SDL_WINDOWEVENT_HIT_TEST ? "SDL_WINDOWEVENT_HIT_TEST" :
      "(UNKNOWN)");
 
   Debug("event:window", "name: '%s', data1: %ld, data2: %ld",
@@ -1449,16 +1459,13 @@ void HandlePauseResumeEvent(PauseResumeEvent *event)
 void HandleKeyEvent(KeyEvent *event)
 {
   int key_status = (event->type == EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
-  boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
-  Key key = GetEventKey(event, with_modifiers);
-  Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
+  Key key = GetEventKey(event);
 
 #if DEBUG_EVENTS_KEY
-  Debug("event:key", "key was %s, keysym.scancode == %d, keysym.sym == %d, keymod = %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
+  Debug("event:key", "key was %s, keysym.scancode == %d, keysym.sym == %d, GetKeyModState() = 0x%04x, resulting key == %d (%s)",
        event->type == EVENT_KEYPRESS ? "pressed" : "released",
        event->keysym.scancode,
        event->keysym.sym,
-       keymod,
        GetKeyModState(),
        key,
        getKeyNameFromKey(key));
@@ -1486,7 +1493,7 @@ void HandleKeyEvent(KeyEvent *event)
   }
 #endif
 
-  HandleKeyModState(keymod, key_status);
+  HandleKeyModState(key, key_status);
 
   // process all keys if not in text input mode or if non-printable keys
   if (!checkTextInputKey(key))
@@ -1545,6 +1552,15 @@ static int HandleDropFileEvent(char *filename)
   // add extracted level or artwork set to tree info structure
   AddTreeSetToTreeInfo(tree_node, directory, top_dir, tree_type);
 
+  // force restart after adding level collection
+  if (getTreeInfoFromIdentifier(TREE_FIRST_NODE(tree_type), top_dir) == NULL)
+  {
+    Request("Program must be restarted after adding a new level collection!",
+           REQ_CONFIRM);
+
+    CloseAllAndExit(0);
+  }
+
   // update menu screen (and possibly change current level set)
   DrawScreenAfterAddingSet(top_dir, tree_type);
 
@@ -1691,6 +1707,7 @@ void HandleButton(int mx, int my, int button, int button_nr)
   static int old_mx = 0, old_my = 0;
   boolean button_hold = FALSE;
   boolean handle_gadgets = TRUE;
+  int game_status_last = game_status;
 
   if (button_nr < 0)
   {
@@ -1709,9 +1726,11 @@ void HandleButton(int mx, int my, int button, int button_nr)
   // when playing, only handle gadgets when using "follow finger" controls
   // or when using touch controls in combination with the MM game engine
   // or when using gadgets that do not overlap with virtual buttons
+  // or when touch controls are disabled (e.g., with mouse-only levels)
   handle_gadgets =
     (game_status != GAME_MODE_PLAYING ||
      level.game_engine_type == GAME_ENGINE_TYPE_MM ||
+     strEqual(setup.touch.control_type, TOUCH_CONTROL_OFF) ||
      strEqual(setup.touch.control_type, TOUCH_CONTROL_FOLLOW_FINGER) ||
      (strEqual(setup.touch.control_type, TOUCH_CONTROL_VIRTUAL_BUTTONS) &&
       !CheckVirtualButtonPressed(mx, my, button)));
@@ -1733,8 +1752,12 @@ void HandleButton(int mx, int my, int button, int button_nr)
 
   if (handle_gadgets && HandleGadgets(mx, my, button))
   {
-    // do not handle this button event anymore
+    // do not handle this button event anymore with position on screen
     mx = my = -32;     // force mouse event to be outside screen tiles
+
+    // do not handle this button event anymore if game status has changed
+    if (game_status != game_status_last)
+      return;
   }
 
   if (button_hold && game_status == GAME_MODE_PLAYING && tape.pausing)
@@ -1772,7 +1795,11 @@ void HandleButton(int mx, int my, int button, int button_nr)
       break;
 
     case GAME_MODE_SCORES:
-      HandleHallOfFame(0, 0, 0, 0, button);
+      HandleHallOfFame(mx, my, 0, 0, button);
+      break;
+
+    case GAME_MODE_SCOREINFO:
+      HandleScoreInfo(mx, my, 0, 0, button);
       break;
 
     case GAME_MODE_EDITOR:
@@ -1959,6 +1986,31 @@ static void HandleKeysSpecial(Key key)
   }
 }
 
+static boolean HandleKeysSpeed(Key key, int key_status)
+{
+  if (game_status == GAME_MODE_PLAYING)
+  {
+    if (key == setup.shortcut.speed_fast ||
+       key == setup.shortcut.speed_slow)
+    {
+      int speed_factor = 4;
+
+      GameFrameDelay = (key_status != KEY_PRESSED ? setup.game_frame_delay :
+                       key == setup.shortcut.speed_fast ? setup.game_frame_delay / speed_factor :
+                       key == setup.shortcut.speed_slow ? setup.game_frame_delay * speed_factor :
+                       setup.game_frame_delay);
+
+      GameFrameDelay = MIN(MAX(1, GameFrameDelay), 1000);
+
+      SetVideoFrameDelay(GameFrameDelay);
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
 boolean HandleKeysDebug(Key key, int key_status)
 {
 #ifdef DEBUG
@@ -2046,6 +2098,9 @@ void HandleKey(Key key, int key_status)
   int joy = 0;
   int i;
 
+  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
 
@@ -2156,6 +2211,10 @@ void HandleKey(Key key, int key_status)
       // for MM style levels, handle in-game keyboard input in HandleJoystick()
       if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
        joy |= key_action;
+
+      // for any keyboard event, enable playfield mouse cursor
+      if (key_action && key_status == KEY_PRESSED)
+       SetPlayfieldMouseCursorEnabled(TRUE);
     }
   }
   else
@@ -2183,6 +2242,10 @@ void HandleKey(Key key, int key_status)
     // reset flag to ignore repeated "key pressed" events after key release
     ignore_repeated_key = FALSE;
 
+    // send key release event to global animation event handling
+    if (!is_global_anim_event)
+      HandleGlobalAnimClicks(-1, -1, KEY_RELEASED, FALSE);
+
     return;
   }
 
@@ -2238,9 +2301,9 @@ void HandleKey(Key key, int key_status)
   }
 
   // some key events are handled like clicks for global animations
-  boolean click = (key == KSYM_space ||
-                  key == KSYM_Return ||
-                  key == KSYM_Escape);
+  boolean click = (!is_global_anim_event && (key == KSYM_space ||
+                                            key == KSYM_Return ||
+                                            key == KSYM_Escape));
 
   if (click && HandleGlobalAnimClicks(-1, -1, MB_LEFTBUTTON, TRUE))
   {
@@ -2265,12 +2328,26 @@ void HandleKey(Key key, int key_status)
     return;
   }
 
+  if (game_status == GAME_MODE_MAIN &&
+      (setup.internal.info_screens_from_main ||
+       leveldir_current->info_screens_from_main) &&
+      (key >= KSYM_KP_1 && key <= KSYM_KP_9))
+  {
+    DrawInfoScreen_FromMainMenu(key - KSYM_KP_1 + 1);
+
+    return;
+  }
+
   if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
   {
     if (key == setup.shortcut.save_game)
       TapeQuickSave();
     else if (key == setup.shortcut.load_game)
       TapeQuickLoad();
+    else if (key == setup.shortcut.restart_game)
+      TapeRestartGame();
+    else if (key == setup.shortcut.pause_before_end)
+      TapeReplayAndPauseBeforeEnd();
     else if (key == setup.shortcut.toggle_pause)
       TapeTogglePause(TAPE_TOGGLE_MANUAL | TAPE_TOGGLE_PLAY_PAUSE);
 
@@ -2278,6 +2355,11 @@ void HandleKey(Key key, int key_status)
     HandleSoundButtonKeys(key);
   }
 
+  if (game_status == GAME_MODE_SCOREINFO)
+  {
+    HandleScreenGadgetKeys(key);
+  }
+
   if (game_status == GAME_MODE_PLAYING && !network_playing)
   {
     int centered_player_nr_next = -999;
@@ -2307,6 +2389,14 @@ void HandleKey(Key key, int key_status)
   if (HandleGadgetsKeyInput(key))
     return;            // do not handle already processed keys again
 
+  // special case: on "space" key, either continue playing or go to main menu
+  if (game_status == GAME_MODE_SCORES && key == KSYM_space)
+  {
+    HandleHallOfFame(0, 0, 0, 0, MB_MENU_CONTINUE);
+
+    return;
+  }
+
   switch (game_status)
   {
     case GAME_MODE_PSEUDO_TYPENAME:
@@ -2322,6 +2412,7 @@ void HandleKey(Key key, int key_status)
     case GAME_MODE_SETUP:
     case GAME_MODE_INFO:
     case GAME_MODE_SCORES:
+    case GAME_MODE_SCOREINFO:
 
       if (anyTextGadgetActiveOrJustFinished && key != KSYM_Escape)
        break;
@@ -2346,6 +2437,8 @@ void HandleKey(Key key, int key_status)
            HandleInfoScreen(0, 0, 0, 0, MB_MENU_CHOICE);
          else if (game_status == GAME_MODE_SCORES)
            HandleHallOfFame(0, 0, 0, 0, MB_MENU_CHOICE);
+         else if (game_status == GAME_MODE_SCOREINFO)
+           HandleScoreInfo(0, 0, 0, 0, MB_MENU_CHOICE);
          break;
 
        case KSYM_Escape:
@@ -2366,6 +2459,8 @@ void HandleKey(Key key, int key_status)
            HandleInfoScreen(0, 0, 0, 0, MB_MENU_LEAVE);
          else if (game_status == GAME_MODE_SCORES)
            HandleHallOfFame(0, 0, 0, 0, MB_MENU_LEAVE);
+         else if (game_status == GAME_MODE_SCOREINFO)
+           HandleScoreInfo(0, 0, 0, 0, MB_MENU_LEAVE);
          break;
 
         case KSYM_Page_Up:
@@ -2381,6 +2476,8 @@ void HandleKey(Key key, int key_status)
            HandleInfoScreen(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
          else if (game_status == GAME_MODE_SCORES)
            HandleHallOfFame(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
+         else if (game_status == GAME_MODE_SCOREINFO)
+           HandleScoreInfo(0, 0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
         case KSYM_Page_Down:
@@ -2396,6 +2493,8 @@ void HandleKey(Key key, int key_status)
            HandleInfoScreen(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
          else if (game_status == GAME_MODE_SCORES)
            HandleHallOfFame(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
+         else if (game_status == GAME_MODE_SCOREINFO)
+           HandleScoreInfo(0, 0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
        default:
@@ -2496,14 +2595,14 @@ static void HandleTileCursor(int dx, int dy, int button)
   {
     int old_xpos = tile_cursor.xpos;
     int old_ypos = tile_cursor.ypos;
-    int new_xpos = old_xpos;
-    int new_ypos = old_ypos;
+    int new_xpos = tile_cursor.xpos + dx;
+    int new_ypos = tile_cursor.ypos + dy;
 
-    if (IN_LEV_FIELD(old_xpos + dx, old_ypos))
-      new_xpos = old_xpos + dx;
+    if (!IN_LEV_FIELD(new_xpos, old_ypos) || !IN_SCR_FIELD(new_xpos, old_ypos))
+      new_xpos = old_xpos;
 
-    if (IN_LEV_FIELD(old_xpos, old_ypos + dy))
-      new_ypos = old_ypos + dy;
+    if (!IN_LEV_FIELD(old_xpos, new_ypos) || !IN_SCR_FIELD(old_xpos, new_ypos))
+      new_ypos = old_ypos;
 
     SetTileCursorTargetXY(new_xpos, new_ypos);
   }
@@ -2544,8 +2643,7 @@ static int HandleJoystickForAllPlayers(void)
 
 void HandleJoystick(void)
 {
-  static unsigned int joytest_delay = 0;
-  static unsigned int joytest_delay_value = GADGET_FRAME_DELAY;
+  static DelayCounter joytest_delay = { GADGET_FRAME_DELAY };
   static int joytest_last = 0;
   int delay_value_first = GADGET_FRAME_DELAY_FIRST;
   int delay_value       = GADGET_FRAME_DELAY;
@@ -2558,12 +2656,15 @@ void HandleJoystick(void)
   int up       = joy & JOY_UP;
   int down     = joy & JOY_DOWN;
   int button   = joy & JOY_BUTTON;
-  int newbutton        = (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED);
+  int anybutton = AnyJoystickButton();
+  int newbutton        = (anybutton == JOY_BUTTON_NEW_PRESSED);
   int dx       = (left ? -1    : right ? 1     : 0);
   int dy       = (up   ? -1    : down  ? 1     : 0);
   boolean use_delay_value_first = (joytest != joytest_last);
+  boolean new_button_event = (anybutton == JOY_BUTTON_NEW_PRESSED ||
+                             anybutton == JOY_BUTTON_NEW_RELEASED);
 
-  if (HandleGlobalAnimClicks(-1, -1, newbutton, FALSE))
+  if (new_button_event && HandleGlobalAnimClicks(-1, -1, newbutton, FALSE))
   {
     // do not handle this button event anymore
     return;
@@ -2599,7 +2700,11 @@ void HandleJoystick(void)
       SetTileCursorEnabled(TRUE);
   }
 
-  if (joytest && !button && !DelayReached(&joytest_delay, joytest_delay_value))
+  // for any joystick event, enable playfield mouse cursor
+  if (dx || dy || button)
+    SetPlayfieldMouseCursorEnabled(TRUE);
+
+  if (joytest && !button && !DelayReached(&joytest_delay))
   {
     // delay joystick/keyboard actions if axes/keys continually pressed
     newbutton = dx = dy = 0;
@@ -2607,7 +2712,7 @@ void HandleJoystick(void)
   else
   {
     // first start with longer delay, then continue with shorter delay
-    joytest_delay_value =
+    joytest_delay.value =
       (use_delay_value_first ? delay_value_first : delay_value);
   }
 
@@ -2623,6 +2728,7 @@ void HandleJoystick(void)
     case GAME_MODE_SETUP:
     case GAME_MODE_INFO:
     case GAME_MODE_SCORES:
+    case GAME_MODE_SCOREINFO:
     {
       if (anyTextGadgetActive())
        break;
@@ -2643,6 +2749,8 @@ void HandleJoystick(void)
        HandleInfoScreen(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
       else if (game_status == GAME_MODE_SCORES)
        HandleHallOfFame(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
+      else if (game_status == GAME_MODE_SCOREINFO)
+       HandleScoreInfo(0,0,dx,dy, newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
 
       break;
     }
@@ -2755,9 +2863,13 @@ boolean DoKeysymAction(int keysym)
   {
     Key key = (Key)(-keysym);
 
+    is_global_anim_event = TRUE;
+
     HandleKey(key, KEY_PRESSED);
     HandleKey(key, KEY_RELEASED);
 
+    is_global_anim_event = FALSE;
+
     return TRUE;
   }
 
index 30a64877dc3b5a4411b5ceb7c2caa4ae60e1dd87..3887f3fdb5d1b4346fb13cb913d90ac325d94fc3 100644 (file)
@@ -21,6 +21,8 @@
 #define USEREVENT_GADGET_PRESSED       3
 
 
+void SetPlayfieldMouseCursorEnabled(boolean);
+
 int FilterMouseMotionEvents(void *, Event *);
 boolean NextValidEvent(Event *);
 void StopProcessingEvents(void);
index 442a0b674b915681014f63d50075ac4cf2928c50..c620a531b37bf4e30517c01366137a61e78edf8e 100644 (file)
 #include "files.h"
 #include "init.h"
 #include "screens.h"
+#include "editor.h"
 #include "tools.h"
 #include "tape.h"
 #include "config.h"
+#include "api.h"
 
 #define ENABLE_UNUSED_CODE     0       // currently unused functions
 #define ENABLE_HISTORIC_CHUNKS 0       // only for historic reference
@@ -51,6 +53,7 @@
 
 // (element number only)
 #define LEVEL_CHUNK_GRPX_UNCHANGED     2
+#define LEVEL_CHUNK_EMPX_UNCHANGED     2
 #define LEVEL_CHUNK_NOTE_UNCHANGED     2
 
 // (nothing at all if unchanged)
@@ -58,7 +61,6 @@
 
 #define TAPE_CHUNK_VERS_SIZE   8       // size of file version chunk
 #define TAPE_CHUNK_HEAD_SIZE   20      // size of tape file header
-#define TAPE_CHUNK_HEAD_UNUSED 1       // unused tape header bytes
 #define TAPE_CHUNK_SCRN_SIZE   2       // size of screen size chunk
 
 #define SCORE_CHUNK_VERS_SIZE  8       // size of file version chunk
                                         CONF_CONTENT_NUM_BYTES : 1)
 
 #define CONF_ELEMENT_BYTE_POS(i)       ((i) * CONF_ELEMENT_NUM_BYTES)
-#define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
+#define CONF_ELEMENTS_ELEMENT(b, i)    ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \
                                        (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
 
 #define CONF_CONTENT_ELEMENT_POS(c,x,y)        ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
@@ -164,7 +166,6 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
     &li.game_engine_type,              GAME_ENGINE_TYPE_RND
   },
-
   {
     -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
@@ -175,102 +176,176 @@ static struct LevelFileConfigInfo chunk_config_INFO[] =
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
     &li.fieldy,                                STD_LEV_FIELDY
   },
-
   {
     -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
     &li.time,                          100
   },
-
   {
     -1,                                        SAVE_CONF_ALWAYS,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
     &li.gems_needed,                   0
   },
-
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_32_BIT(2),
     &li.random_seed,                   0
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
     &li.use_step_counter,              FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
     &li.wind_direction_initial,                MV_NONE
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
     &li.em_slippery_gems,              FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
     &li.use_custom_template,           FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
     &li.can_move_into_acid_bits,       ~0      // default: everything can
   },
-
   {
     -1,                                        -1,
     TYPE_BITFIELD,                     CONF_VALUE_8_BIT(7),
     &li.dont_collide_with_bits,                ~0      // default: always deadly
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
     &li.em_explodes_by_fire,           FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
     &li.score[SC_TIME_BONUS],          1
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
     &li.auto_exit_sokoban,             FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
     &li.auto_count_gems,               FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
     &li.solved_by_one_player,          FALSE
   },
-
   {
     -1,                                        -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(12),
     &li.time_score_base,               1
   },
-
   {
     -1,                                        -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
     &li.rate_time_over_score,          FALSE
   },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(14),
+    &li.bd_intermission,               FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(15),
+    &li.bd_scheduling_type,            GD_SCHEDULING_MILLISECONDS
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(16),
+    &li.bd_pal_timing,                 FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &li.bd_cycle_delay_ms,             200
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(17),
+    &li.bd_cycle_delay_c64,            0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(18),
+    &li.bd_hatching_delay_cycles,      21
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(19),
+    &li.bd_hatching_delay_seconds,     2
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(20),
+    &li.bd_line_shifting_borders,      FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(21),
+    &li.bd_scan_first_and_last_row,    TRUE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(22),
+    &li.bd_short_explosions,           TRUE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(23),
+    &li.bd_cave_random_seed_c64,       0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(3),
+    &li.bd_color_b,                    GD_C64_COLOR(0)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(4),
+    &li.bd_color_0,                    GD_C64_COLOR(0)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(5),
+    &li.bd_color_1,                    GD_C64_COLOR(8)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(6),
+    &li.bd_color_2,                    GD_C64_COLOR(11)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(7),
+    &li.bd_color_3,                    GD_C64_COLOR(1)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(8),
+    &li.bd_color_4,                    GD_C64_COLOR(5)
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(9),
+    &li.bd_color_5,                    GD_C64_COLOR(6)
+  },
 
   {
     -1,                                        -1,
@@ -562,771 +637,1293 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     &li.initial_inventory_size[3],     1, MAX_INITIAL_INVENTORY_SIZE
   },
 
+  // (these values are only valid for BD style levels)
+  // (some values for BD style amoeba following below)
   {
-    EL_EMERALD,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_EMERALD],             10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_diagonal_movements,         FALSE
   },
-
   {
-    EL_DIAMOND,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_DIAMOND],             10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.bd_topmost_player_active,      TRUE
   },
-
   {
-    EL_BUG,                            -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_BUG],                 10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.bd_pushing_prob,               25
   },
-
   {
-    EL_SPACESHIP,                      -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_SPACESHIP],           10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
+    &li.bd_pushing_prob_with_sweet,    100
   },
-
   {
-    EL_PACMAN,                         -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_PACMAN],              10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.bd_push_mega_rock_with_sweet,  FALSE
   },
-
   {
-    EL_NUT,                            -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_NUT],                 10
+    EL_BDX_PLAYER,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
+    &li.bd_snap_element,               EL_EMPTY
   },
 
   {
-    EL_DYNAMITE,                       -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_DYNAMITE],            10
+    EL_BDX_SAND_1,                     -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_sand_looks_like,            EL_BDX_SAND_1
   },
 
   {
-    EL_KEY_1,                          -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_KEY],                 10
+    EL_BDX_ROCK,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_rock_turns_to_on_falling,   EL_BDX_ROCK_FALLING
   },
-
   {
-    EL_PEARL,                          -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_PEARL],               10
+    EL_BDX_ROCK,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.bd_rock_turns_to_on_impact,    EL_BDX_ROCK
   },
 
   {
-    EL_CRYSTAL,                                -1,
+    EL_BDX_DIAMOND,                    -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_CRYSTAL],             10
+    &li.score[SC_DIAMOND_EXTRA],       20
+  },
+  {
+    EL_BDX_DIAMOND,                    -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.bd_diamond_turns_to_on_falling,        EL_BDX_DIAMOND_FALLING
+  },
+  {
+    EL_BDX_DIAMOND,                    -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.bd_diamond_turns_to_on_impact, EL_BDX_DIAMOND
   },
 
   {
-    EL_BD_AMOEBA,                      -1,
+    EL_BDX_FIREFLY_1,                  -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &li.amoeba_content,                        EL_DIAMOND
+    &li.bd_firefly_1_explodes_to,      EL_BDX_EXPLODING_1
   },
+
   {
-    EL_BD_AMOEBA,                      -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.amoeba_speed,                  10
+    EL_BDX_FIREFLY_2,                  -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_firefly_2_explodes_to,      EL_BDX_EXPLODING_1
   },
+
   {
-    EL_BD_AMOEBA,                      -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.grow_into_diggable,            TRUE
+    EL_BDX_BUTTERFLY_1,                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_butterfly_1_explodes_to,    EL_BDX_DIAMOND_GROWING_1
   },
 
   {
-    EL_YAMYAM,                         -1,
-    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
-    &li.yamyam_content,                        EL_ROCK, NULL,
-    &li.num_yamyam_contents,           4, MAX_ELEMENT_CONTENTS
+    EL_BDX_BUTTERFLY_2,                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_butterfly_2_explodes_to,    EL_BDX_DIAMOND_GROWING_1
   },
+
   {
-    EL_YAMYAM,                         -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_YAMYAM],              10
+    EL_BDX_STONEFLY,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_stonefly_explodes_to,       EL_BDX_ROCK_GROWING_1
   },
 
   {
-    EL_ROBOT,                          -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_ROBOT],               10
+    EL_BDX_DRAGONFLY,                  -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_dragonfly_explodes_to,      EL_BDX_EXPLODING_1
   },
+
   {
-    EL_ROBOT,                          -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.slurp_score,                   10
+    EL_BDX_DIAMOND_GROWING_5,  -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_diamond_birth_turns_to,     EL_BDX_DIAMOND
   },
 
   {
-    EL_ROBOT_WHEEL,                    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.time_wheel,                    10
+    EL_BDX_BOMB_EXPLODING_4,           -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_bomb_explosion_turns_to,    EL_BDX_WALL
   },
 
   {
-    EL_MAGIC_WALL,                     -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.time_magic_wall,               10
+    EL_BDX_NITRO_PACK_EXPLODING_4,     -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_nitro_explosion_turns_to,   EL_EMPTY
   },
 
   {
-    EL_GAME_OF_LIFE,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &li.game_of_life[0],               2
+    EL_BDX_EXPLODING_5,                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_explosion_turns_to,         EL_EMPTY
   },
+
   {
-    EL_GAME_OF_LIFE,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
-    &li.game_of_life[1],               3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_magic_wall_wait_hatching,   FALSE
   },
   {
-    EL_GAME_OF_LIFE,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
-    &li.game_of_life[2],               3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.bd_magic_wall_stops_amoeba,    TRUE
   },
   {
-    EL_GAME_OF_LIFE,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
-    &li.game_of_life[3],               3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.bd_magic_wall_zero_infinite,   TRUE
   },
   {
-    EL_GAME_OF_LIFE,                   -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
-    &li.use_life_bugs,                 FALSE
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.bd_magic_wall_break_scan,      FALSE
   },
-
   {
-    EL_BIOMAZE,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &li.biomaze[0],                    2
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.bd_magic_wall_time,            999
   },
   {
-    EL_BIOMAZE,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
-    &li.biomaze[1],                    3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.bd_magic_wall_diamond_to,      EL_BDX_ROCK_FALLING
   },
   {
-    EL_BIOMAZE,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
-    &li.biomaze[2],                    3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.bd_magic_wall_rock_to,         EL_BDX_DIAMOND_FALLING
   },
   {
-    EL_BIOMAZE,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
-    &li.biomaze[3],                    3
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(4),
+    &li.bd_magic_wall_mega_rock_to,    EL_BDX_NITRO_PACK_FALLING
   },
-
   {
-    EL_TIMEGATE_SWITCH,                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.time_timegate,                 10
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &li.bd_magic_wall_nut_to,          EL_BDX_NUT_FALLING
   },
-
   {
-    EL_LIGHT_SWITCH_ACTIVE,            -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.time_light,                    10
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(6),
+    &li.bd_magic_wall_nitro_pack_to,   EL_BDX_MEGA_ROCK_FALLING
   },
-
   {
-    EL_SHIELD_NORMAL,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.shield_normal_time,            10
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(7),
+    &li.bd_magic_wall_flying_diamond_to, EL_BDX_FLYING_ROCK_FLYING
   },
   {
-    EL_SHIELD_NORMAL,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.score[SC_SHIELD],              10
+    EL_BDX_MAGIC_WALL,                 -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(8),
+    &li.bd_magic_wall_flying_rock_to,  EL_BDX_FLYING_DIAMOND_FLYING
   },
 
   {
-    EL_SHIELD_DEADLY,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.shield_deadly_time,            10
+    EL_BDX_CLOCK,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_clock_extra_time,           30
   },
+
   {
-    EL_SHIELD_DEADLY,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.score[SC_SHIELD],              10
+    EL_BDX_VOODOO_DOLL,                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_voodoo_collects_diamonds,   FALSE
   },
-
   {
-    EL_EXTRA_TIME,                     -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.extra_time,                    10
+    EL_BDX_VOODOO_DOLL,                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.bd_voodoo_hurt_kills_player,   FALSE
   },
   {
-    EL_EXTRA_TIME,                     -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.extra_time_score,              10
+    EL_BDX_VOODOO_DOLL,                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.bd_voodoo_dies_by_rock,                FALSE
   },
-
   {
-    EL_TIME_ORB_FULL,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.time_orb_time,                 10
+    EL_BDX_VOODOO_DOLL,                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.bd_voodoo_vanish_by_explosion, TRUE
   },
   {
-    EL_TIME_ORB_FULL,                  -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.use_time_orb_bug,              FALSE
+    EL_BDX_VOODOO_DOLL,                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
+    &li.bd_voodoo_penalty_time,                30
   },
 
   {
-    EL_SPRING,                         -1,
+    EL_BDX_SLIME,                      -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.use_spring_bug,                        FALSE
+    &li.bd_slime_is_predictable,       TRUE
   },
-
   {
-    EL_EMC_ANDROID,                    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.android_move_time,             10
+    EL_BDX_SLIME,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.bd_slime_permeability_rate,    100
   },
   {
-    EL_EMC_ANDROID,                    -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.android_clone_time,            10
+    EL_BDX_SLIME,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.bd_slime_permeability_bits_c64,        0
   },
   {
-    EL_EMC_ANDROID,                    SAVE_CONF_NEVER,
-    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
-    &li.android_clone_element[0],      EL_EMPTY, NULL,
-    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS_OLD
+    EL_BDX_SLIME,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_32_BIT(1),
+    &li.bd_slime_random_seed_c64,      -1
   },
   {
-    EL_EMC_ANDROID,                    -1,
-    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(2),
-    &li.android_clone_element[0],      EL_EMPTY, NULL,
-    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_slime_eats_element_1,       EL_BDX_DIAMOND
   },
-
   {
-    EL_EMC_LENSES,                     -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.lenses_score,                  10
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.bd_slime_converts_to_element_1,        EL_BDX_DIAMOND_FALLING
   },
   {
-    EL_EMC_LENSES,                     -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.lenses_time,                   10
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.bd_slime_eats_element_2,       EL_BDX_ROCK
   },
-
   {
-    EL_EMC_MAGNIFIER,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.magnify_score,                 10
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(4),
+    &li.bd_slime_converts_to_element_2,        EL_BDX_ROCK_FALLING
   },
   {
-    EL_EMC_MAGNIFIER,                  -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &li.magnify_time,                  10
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &li.bd_slime_eats_element_3,       EL_BDX_NUT
+  },
+  {
+    EL_BDX_SLIME,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(6),
+    &li.bd_slime_converts_to_element_3,        EL_BDX_NUT_FALLING
   },
 
   {
-    EL_EMC_MAGIC_BALL,                 -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.ball_time,                     10
+    EL_BDX_ACID,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_acid_eats_element,          EL_BDX_SAND_1
   },
   {
-    EL_EMC_MAGIC_BALL,                 -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.ball_random,                   FALSE
+    EL_BDX_ACID,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_acid_spread_rate,           3
   },
   {
-    EL_EMC_MAGIC_BALL,                 -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &li.ball_active_initial,           FALSE
+    EL_BDX_ACID,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.bd_acid_turns_to_element,      EL_BDX_EXPLODING_3
+  },
+
+  {
+    EL_BDX_BITER,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_biter_move_delay,           0
   },
   {
-    EL_EMC_MAGIC_BALL,                 -1,
-    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
-    &li.ball_content,                  EL_EMPTY, NULL,
-    &li.num_ball_contents,             4, MAX_ELEMENT_CONTENTS
+    EL_BDX_BITER,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_biter_eats_element,         EL_BDX_DIAMOND
   },
 
   {
-    EL_SOKOBAN_FIELD_EMPTY,            -1,
+    EL_BDX_BLADDER,                    -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_bladder_converts_by_element,        EL_BDX_VOODOO_DOLL
+  },
+
+  {
+    EL_BDX_EXPANDABLE_WALL_ANY,                -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.sb_fields_needed,              TRUE
+    &li.bd_change_expanding_wall,      FALSE
+  },
+  {
+    EL_BDX_EXPANDABLE_WALL_ANY,                -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_expanding_wall_looks_like,  EL_BDX_WALL
   },
 
   {
-    EL_SOKOBAN_OBJECT,                 -1,
+    EL_BDX_REPLICATOR,                 -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.sb_objects_needed,             TRUE
+    &li.bd_replicators_active,         TRUE
+  },
+  {
+    EL_BDX_REPLICATOR,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.bd_replicator_create_delay,    4
   },
 
   {
-    EL_MM_MCDUFFIN,                    -1,
+    EL_BDX_CONVEYOR_LEFT,              -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.mm_laser_red,                  FALSE
+    &li.bd_conveyor_belts_active,      TRUE
   },
   {
-    EL_MM_MCDUFFIN,                    -1,
+    EL_BDX_CONVEYOR_LEFT,              -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &li.mm_laser_green,                        FALSE
+    &li.bd_conveyor_belts_changed,     FALSE
   },
+
   {
-    EL_MM_MCDUFFIN,                    -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
-    &li.mm_laser_blue,                 TRUE
+    EL_BDX_WATER,                      -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_water_cannot_flow_down,     FALSE
   },
 
   {
-    EL_DF_LASER,                       -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &li.df_laser_red,                  TRUE
+    EL_BDX_NUT,                                -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.bd_nut_content,                        EL_BDX_NUT_BREAKING_1
+  },
+
+  {
+    EL_BDX_PNEUMATIC_HAMMER,           -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_hammer_walls_break_delay,   5
   },
   {
-    EL_DF_LASER,                       -1,
+    EL_BDX_PNEUMATIC_HAMMER,           -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &li.df_laser_green,                        TRUE
+    &li.bd_hammer_walls_reappear,      FALSE
   },
   {
-    EL_DF_LASER,                       -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
-    &li.df_laser_blue,                 FALSE
+    EL_BDX_PNEUMATIC_HAMMER,           -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.bd_hammer_walls_reappear_delay,        100
   },
 
   {
-    EL_MM_FUSE_ACTIVE,                 -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.mm_time_fuse,                  25
+    EL_BDX_ROCKET_LAUNCHER,            -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_infinite_rockets,           FALSE
   },
+
   {
-    EL_MM_BOMB,                                -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.mm_time_bomb,                  75
+    EL_BDX_SKELETON,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_num_skeletons_needed_for_pot, 5
   },
   {
-    EL_MM_GRAY_BALL,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.mm_time_ball,                  75
+    EL_BDX_SKELETON,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.bd_skeleton_worth_num_diamonds,        0
   },
+
   {
-    EL_MM_STEEL_BLOCK,                 -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.mm_time_block,                 75
+    EL_BDX_CREATURE_SWITCH,            -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.bd_creatures_start_backwards,  FALSE
   },
   {
-    EL_MM_LIGHTBALL,                   -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_ELEM_BONUS],          10
+    EL_BDX_CREATURE_SWITCH,            -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.bd_creatures_turn_on_hatching, FALSE
   },
-
-  // ---------- unused values -------------------------------------------------
-
   {
-    EL_UNKNOWN,                                SAVE_CONF_NEVER,
+    EL_BDX_CREATURE_SWITCH,            -1,
     TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
-    &li.score[SC_UNKNOWN_15],          10
+    &li.bd_creatures_auto_turn_delay,  0
   },
 
   {
-    -1,                                        -1,
-    -1,                                        -1,
-    NULL,                              -1
-  }
-};
-
-static struct LevelFileConfigInfo chunk_config_NOTE[] =
-{
-  {
-    -1,                                        -1,
+    EL_BDX_GRAVITY_SWITCH,             -1,
     TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &xx_envelope.xsize,                        MAX_ENVELOPE_XSIZE,
+    &li.bd_gravity_direction,          GD_MV_DOWN
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
-    &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
+    EL_BDX_GRAVITY_SWITCH,             -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.bd_gravity_switch_active,      FALSE
   },
-
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
-    &xx_envelope.autowrap,             FALSE
+    EL_BDX_GRAVITY_SWITCH,             -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.bd_gravity_switch_delay,       10
   },
   {
-    -1,                                        -1,
+    EL_BDX_GRAVITY_SWITCH,             -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
-    &xx_envelope.centered,             FALSE
+    &li.bd_gravity_affects_all,                TRUE
   },
 
+  // (the following values are related to various game elements)
+
   {
-    -1,                                        -1,
-    TYPE_STRING,                       CONF_VALUE_BYTES(1),
-    &xx_envelope.text,                 -1, NULL,
-    &xx_string_length_unused,          -1, MAX_ENVELOPE_TEXT_LEN,
-    &xx_default_string_empty[0]
+    EL_EMERALD,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_EMERALD],             10
   },
 
   {
-    -1,                                        -1,
-    -1,                                        -1,
-    NULL,                              -1
-  }
-};
+    EL_DIAMOND,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DIAMOND],             10
+  },
 
-static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
-{
   {
-    -1,                                        -1,
-    TYPE_STRING,                       CONF_VALUE_BYTES(1),
-    &xx_ei.description[0],             -1,
-    &yy_ei.description[0],
-    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
-    &xx_default_description[0]
+    EL_BUG,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_BUG],                 10
   },
 
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
-    &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
-    &yy_ei.properties[EP_BITFIELD_BASE_NR]
+    EL_SPACESHIP,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_SPACESHIP],           10
   },
-#if ENABLE_RESERVED_CODE
-  // (reserved for later use)
+
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
-    &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
-    &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
+    EL_PACMAN,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PACMAN],              10
   },
-#endif
 
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
-    &xx_ei.use_gfx_element,            FALSE,
-    &yy_ei.use_gfx_element
+    EL_NUT,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_NUT],                 10
   },
+
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE,
-    &yy_ei.gfx_element_initial
+    EL_DYNAMITE,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DYNAMITE],            10
   },
 
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(2),
-    &xx_ei.access_direction,           MV_ALL_DIRECTIONS,
-    &yy_ei.access_direction
+    EL_KEY_1,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_KEY],                 10
   },
 
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &xx_ei.collect_score_initial,      10,
-    &yy_ei.collect_score_initial
+    EL_PEARL,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PEARL],               10
   },
+
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
-    &xx_ei.collect_count_initial,      1,
-    &yy_ei.collect_count_initial
+    EL_CRYSTAL,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_CRYSTAL],             10
   },
 
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
-    &xx_ei.ce_value_fixed_initial,     0,
-    &yy_ei.ce_value_fixed_initial
+    EL_BD_AMOEBA,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.amoeba_content,                        EL_DIAMOND
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
-    &xx_ei.ce_value_random_initial,    0,
-    &yy_ei.ce_value_random_initial
+    EL_BD_AMOEBA,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.amoeba_speed,                  10
   },
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
-    &xx_ei.use_last_ce_value,          FALSE,
-    &yy_ei.use_last_ce_value
+    EL_BD_AMOEBA,                      -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.grow_into_diggable,            TRUE
   },
 
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
-    &xx_ei.push_delay_fixed,           8,
-    &yy_ei.push_delay_fixed
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.bd_amoeba_1_threshold_too_big, 200
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(7),
-    &xx_ei.push_delay_random,          8,
-    &yy_ei.push_delay_random
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.bd_amoeba_1_slow_growth_time,  200
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(8),
-    &xx_ei.drop_delay_fixed,           0,
-    &yy_ei.drop_delay_fixed
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.bd_amoeba_1_content_too_big,   EL_BDX_ROCK
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(9),
-    &xx_ei.drop_delay_random,          0,
-    &yy_ei.drop_delay_random
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(4),
+    &li.bd_amoeba_1_content_enclosed,  EL_BDX_DIAMOND
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(10),
-    &xx_ei.move_delay_fixed,           0,
-    &yy_ei.move_delay_fixed
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_amoeba_1_slow_growth_rate,  3
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(11),
-    &xx_ei.move_delay_random,          0,
-    &yy_ei.move_delay_random
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.bd_amoeba_1_fast_growth_rate,  25
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(16),
-    &xx_ei.step_delay_fixed,           0,
-    &yy_ei.step_delay_fixed
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.bd_amoeba_wait_for_hatching,   FALSE
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(17),
-    &xx_ei.step_delay_random,          0,
-    &yy_ei.step_delay_random
+    EL_BDX_AMOEBA_1,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.bd_amoeba_start_immediately,   TRUE
   },
 
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
-    &xx_ei.move_pattern,               MV_ALL_DIRECTIONS,
-    &yy_ei.move_pattern
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.bd_amoeba_2_threshold_too_big, 200
   },
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
-    &xx_ei.move_direction_initial,     MV_START_AUTOMATIC,
-    &yy_ei.move_direction_initial
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.bd_amoeba_2_slow_growth_time,  200
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
-    &xx_ei.move_stepsize,              TILEX / 8,
-    &yy_ei.move_stepsize
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.bd_amoeba_2_content_too_big,   EL_BDX_ROCK
   },
-
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(12),
-    &xx_ei.move_enter_element,         EL_EMPTY_SPACE,
-    &yy_ei.move_enter_element
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(4),
+    &li.bd_amoeba_2_content_enclosed,  EL_BDX_DIAMOND
   },
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(13),
-    &xx_ei.move_leave_element,         EL_EMPTY_SPACE,
-    &yy_ei.move_leave_element
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &li.bd_amoeba_2_content_exploding, EL_EMPTY
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
-    &xx_ei.move_leave_type,            LEAVE_TYPE_UNLIMITED,
-    &yy_ei.move_leave_type
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(6),
+    &li.bd_amoeba_2_content_looks_like,        EL_BDX_AMOEBA_2
   },
-
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
-    &xx_ei.slippery_type,              SLIPPERY_ANY_RANDOM,
-    &yy_ei.slippery_type
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.bd_amoeba_2_slow_growth_rate,  3
   },
-
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(8),
-    &xx_ei.explosion_type,             EXPLODES_3X3,
-    &yy_ei.explosion_type
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.bd_amoeba_2_fast_growth_rate,  25
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(14),
-    &xx_ei.explosion_delay,            16,
-    &yy_ei.explosion_delay
+    EL_BDX_AMOEBA_2,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.bd_amoeba_2_explode_by_amoeba, TRUE
   },
+
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(15),
-    &xx_ei.ignition_delay,             8,
-    &yy_ei.ignition_delay
+    EL_YAMYAM,                         -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.yamyam_content,                        EL_ROCK, NULL,
+    &li.num_yamyam_contents,           4, MAX_ELEMENT_CONTENTS
   },
-
   {
-    -1,                                        -1,
-    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(2),
-    &xx_ei.content,                    EL_EMPTY_SPACE,
-    &yy_ei.content,
-    &xx_num_contents,                  1, 1
+    EL_YAMYAM,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_YAMYAM],              10
   },
 
-  // ---------- "num_change_pages" must be the last entry ---------------------
-
   {
-    -1,                                        SAVE_CONF_ALWAYS,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(9),
-    &xx_ei.num_change_pages,           1,
-    &yy_ei.num_change_pages
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_ROBOT],               10
   },
-
   {
-    -1,                                        -1,
-    -1,                                        -1,
-    NULL,                              -1,
-    NULL
-  }
-};
-
-static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
-{
-  // ---------- "current_change_page" must be the first entry -----------------
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.slurp_score,                   10
+  },
 
   {
-    -1,                                        SAVE_CONF_ALWAYS,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
-    &xx_current_change_page,           -1
+    EL_ROBOT_WHEEL,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_wheel,                    10
   },
 
-  // ---------- (the remaining entries can be in any order) -------------------
-
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &xx_change.can_change,             FALSE
+    EL_MAGIC_WALL,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_magic_wall,               10
   },
 
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
-    &xx_event_bits[0],                 0
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.game_of_life[0],               2
   },
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
-    &xx_event_bits[1],                 0
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.game_of_life[1],               3
   },
-
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(3),
-    &xx_change.trigger_player,         CH_PLAYER_ANY
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.game_of_life[2],               3
   },
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
-    &xx_change.trigger_side,           CH_SIDE_ANY
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
+    &li.game_of_life[3],               3
   },
   {
-    -1,                                        -1,
-    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
-    &xx_change.trigger_page,           CH_PAGE_ANY
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.use_life_bugs,                 FALSE
   },
 
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
-    &xx_change.target_element,         EL_EMPTY_SPACE
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.biomaze[0],                    2
   },
-
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
-    &xx_change.delay_fixed,            0
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.biomaze[1],                    3
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
-    &xx_change.delay_random,           0
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.biomaze[2],                    3
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
-    &xx_change.delay_frames,           FRAMES_PER_SECOND
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
+    &li.biomaze[3],                    3
   },
 
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
-    &xx_change.initial_trigger_element,        EL_EMPTY_SPACE
+    EL_TIMEGATE_SWITCH,                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_timegate,                 10
   },
 
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
-    &xx_change.explode,                        FALSE
-  },
-  {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(7),
-    &xx_change.use_target_content,     FALSE
+    EL_LIGHT_SWITCH_ACTIVE,            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_light,                    10
   },
+
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
-    &xx_change.only_if_complete,       FALSE
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.shield_normal_time,            10
   },
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
-    &xx_change.use_random_replace,     FALSE
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
   },
+
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(10),
-    &xx_change.random_percentage,      100
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.shield_deadly_time,            10
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(11),
-    &xx_change.replace_when,           CP_WHEN_EMPTY
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
   },
 
   {
-    -1,                                        -1,
-    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
-    &xx_change.has_action,             FALSE
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.extra_time,                    10
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(13),
-    &xx_change.action_type,            CA_NO_ACTION
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.extra_time_score,              10
   },
+
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_8_BIT(14),
-    &xx_change.action_mode,            CA_MODE_UNDEFINED
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_orb_time,                 10
   },
   {
-    -1,                                        -1,
-    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
-    &xx_change.action_arg,             CA_ARG_UNDEFINED
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_time_orb_bug,              FALSE
   },
 
   {
-    -1,                                        -1,
-    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(7),
-    &xx_change.action_element,         EL_EMPTY_SPACE
+    EL_SPRING,                         -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_spring_bug,                        FALSE
   },
 
   {
-    -1,                                        -1,
-    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
-    &xx_change.target_content,         EL_EMPTY_SPACE, NULL,
-    &xx_num_contents,                  1, 1
-  },
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.android_move_time,             10
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.android_clone_time,            10
+  },
+  {
+    EL_EMC_ANDROID,                    SAVE_CONF_NEVER,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.android_clone_element[0],      EL_EMPTY, NULL,
+    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS_OLD
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(2),
+    &li.android_clone_element[0],      EL_EMPTY, NULL,
+    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS
+  },
+
+  {
+    EL_EMC_LENSES,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.lenses_score,                  10
+  },
+  {
+    EL_EMC_LENSES,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.lenses_time,                   10
+  },
+
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.magnify_score,                 10
+  },
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.magnify_time,                  10
+  },
+
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.ball_time,                     10
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.ball_random,                   FALSE
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.ball_active_initial,           FALSE
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.ball_content,                  EL_EMPTY, NULL,
+    &li.num_ball_contents,             4, MAX_ELEMENT_CONTENTS
+  },
+
+  {
+    EL_SOKOBAN_FIELD_EMPTY,            -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.sb_fields_needed,              TRUE
+  },
+
+  {
+    EL_SOKOBAN_OBJECT,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.sb_objects_needed,             TRUE
+  },
+
+  {
+    EL_MM_MCDUFFIN,                    -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.mm_laser_red,                  FALSE
+  },
+  {
+    EL_MM_MCDUFFIN,                    -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.mm_laser_green,                        FALSE
+  },
+  {
+    EL_MM_MCDUFFIN,                    -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.mm_laser_blue,                 TRUE
+  },
+
+  {
+    EL_DF_LASER,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.df_laser_red,                  TRUE
+  },
+  {
+    EL_DF_LASER,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.df_laser_green,                        TRUE
+  },
+  {
+    EL_DF_LASER,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.df_laser_blue,                 FALSE
+  },
+
+  {
+    EL_MM_FUSE_ACTIVE,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.mm_time_fuse,                  25
+  },
+  {
+    EL_MM_BOMB,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.mm_time_bomb,                  75
+  },
+
+  {
+    EL_MM_GRAY_BALL,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.mm_time_ball,                  75
+  },
+  {
+    EL_MM_GRAY_BALL,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.mm_ball_choice_mode,           ANIM_RANDOM
+  },
+  {
+    EL_MM_GRAY_BALL,                   -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.mm_ball_content,               EL_EMPTY, NULL,
+    &li.num_mm_ball_contents,          8, MAX_MM_BALL_CONTENTS
+  },
+  {
+    EL_MM_GRAY_BALL,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.rotate_mm_ball_content,                TRUE
+  },
+  {
+    EL_MM_GRAY_BALL,                   -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.explode_mm_ball,               FALSE
+  },
+
+  {
+    EL_MM_STEEL_BLOCK,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.mm_time_block,                 75
+  },
+  {
+    EL_MM_LIGHTBALL,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_ELEM_BONUS],          10
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_NOTE[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_envelope.xsize,                        MAX_ENVELOPE_XSIZE,
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_envelope.autowrap,             FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &xx_envelope.centered,             FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_envelope.text,                 -1, NULL,
+    &xx_string_length_unused,          -1, MAX_ENVELOPE_TEXT_LEN,
+    &xx_default_string_empty[0]
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_ei.description[0],             -1,
+    &yy_ei.description[0],
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
+    &xx_default_description[0]
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
+    &yy_ei.properties[EP_BITFIELD_BASE_NR]
+  },
+#if ENABLE_RESERVED_CODE
+  // (reserved for later use)
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
+    &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
+    &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
+  },
+#endif
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE,
+    &yy_ei.use_gfx_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE,
+    &yy_ei.gfx_element_initial
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(2),
+    &xx_ei.access_direction,           MV_ALL_DIRECTIONS,
+    &yy_ei.access_direction
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_ei.collect_score_initial,      10,
+    &yy_ei.collect_score_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_ei.collect_count_initial,      1,
+    &yy_ei.collect_count_initial
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_ei.ce_value_fixed_initial,     0,
+    &yy_ei.ce_value_fixed_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &xx_ei.ce_value_random_initial,    0,
+    &yy_ei.ce_value_random_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_ei.use_last_ce_value,          FALSE,
+    &yy_ei.use_last_ce_value
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_ei.push_delay_fixed,           8,
+    &yy_ei.push_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(7),
+    &xx_ei.push_delay_random,          8,
+    &yy_ei.push_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(8),
+    &xx_ei.drop_delay_fixed,           0,
+    &yy_ei.drop_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(9),
+    &xx_ei.drop_delay_random,          0,
+    &yy_ei.drop_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(10),
+    &xx_ei.move_delay_fixed,           0,
+    &yy_ei.move_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(11),
+    &xx_ei.move_delay_random,          0,
+    &yy_ei.move_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(16),
+    &xx_ei.step_delay_fixed,           0,
+    &yy_ei.step_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(17),
+    &xx_ei.step_delay_random,          0,
+    &yy_ei.step_delay_random
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_ei.move_pattern,               MV_ALL_DIRECTIONS,
+    &yy_ei.move_pattern
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_ei.move_direction_initial,     MV_START_AUTOMATIC,
+    &yy_ei.move_direction_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
+    &xx_ei.move_stepsize,              TILEX / 8,
+    &yy_ei.move_stepsize
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(12),
+    &xx_ei.move_enter_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_enter_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(13),
+    &xx_ei.move_leave_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_leave_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
+    &xx_ei.move_leave_type,            LEAVE_TYPE_UNLIMITED,
+    &yy_ei.move_leave_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &xx_ei.slippery_type,              SLIPPERY_ANY_RANDOM,
+    &yy_ei.slippery_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(8),
+    &xx_ei.explosion_type,             EXPLODES_3X3,
+    &yy_ei.explosion_type
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(14),
+    &xx_ei.explosion_delay,            16,
+    &yy_ei.explosion_delay
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(15),
+    &xx_ei.ignition_delay,             8,
+    &yy_ei.ignition_delay
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(2),
+    &xx_ei.content,                    EL_EMPTY_SPACE,
+    &yy_ei.content,
+    &xx_num_contents,                  1, 1
+  },
+
+  // ---------- "num_change_pages" must be the last entry ---------------------
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(9),
+    &xx_ei.num_change_pages,           1,
+    &yy_ei.num_change_pages
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1,
+    NULL
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
+{
+  // ---------- "current_change_page" must be the first entry -----------------
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_current_change_page,           -1
+  },
+
+  // ---------- (the remaining entries can be in any order) -------------------
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &xx_change.can_change,             FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_event_bits[0],                 0
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
+    &xx_event_bits[1],                 0
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(3),
+    &xx_change.trigger_player,         CH_PLAYER_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_change.trigger_side,           CH_SIDE_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_change.trigger_page,           CH_PAGE_ANY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_change.target_element,         EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_change.delay_fixed,            0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_change.delay_random,           0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_change.delay_frames,           FRAMES_PER_SECOND
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &xx_change.initial_trigger_element,        EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &xx_change.explode,                        FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(7),
+    &xx_change.use_target_content,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &xx_change.only_if_complete,       FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &xx_change.use_random_replace,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(10),
+    &xx_change.random_percentage,      100
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(11),
+    &xx_change.replace_when,           CP_WHEN_EMPTY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &xx_change.has_action,             FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(13),
+    &xx_change.action_type,            CA_NO_ACTION
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(14),
+    &xx_change.action_mode,            CA_MODE_UNDEFINED
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_change.action_arg,             CA_ARG_UNDEFINED
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(7),
+    &xx_change.action_element,         EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &xx_change.target_content,         EL_EMPTY_SPACE, NULL,
+    &xx_num_contents,                  1, 1
+  },
 
   {
     -1,                                        -1,
@@ -1376,6 +1973,26 @@ static struct LevelFileConfigInfo chunk_config_GRPX[] =
   }
 };
 
+static struct LevelFileConfigInfo chunk_config_EMPX[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element_initial,                EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
 static struct LevelFileConfigInfo chunk_config_CONF[] =                // (OBSOLETE)
 {
   {
@@ -1721,16 +2338,23 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 
 static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
 {
+  boolean add_border = FALSE;
+  int x1 = 0;
+  int y1 = 0;
+  int x2 = STD_LEV_FIELDX - 1;
+  int y2 = STD_LEV_FIELDY - 1;
   int i, x, y;
 
   li = *level;         // copy level data into temporary buffer
   setConfigToDefaultsFromConfigList(chunk_config_INFO);
   *level = li;         // copy temporary buffer back to level data
 
+  setLevelInfoToDefaults_BD();
   setLevelInfoToDefaults_EM();
   setLevelInfoToDefaults_SP();
   setLevelInfoToDefaults_MM();
 
+  level->native_bd_level = &native_bd_level;
   level->native_em_level = &native_em_level;
   level->native_sp_level = &native_sp_level;
   level->native_mm_level = &native_mm_level;
@@ -1754,19 +2378,49 @@ static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
   strcpy(level->name, NAMELESS_LEVEL_NAME);
   strcpy(level->author, ANONYMOUS_NAME);
 
+  // set default game engine type
+  level->game_engine_type = setup.default_game_engine_type;
+
+  // some game engines should have a default playfield with border elements
+  if (level->game_engine_type == GAME_ENGINE_TYPE_BD ||
+      level->game_engine_type == GAME_ENGINE_TYPE_EM ||
+      level->game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    add_border = TRUE;
+    x1++;
+    y1++;
+    x2--;
+    y2--;
+  }
+
   // set level playfield to playable default level with player and exit
   for (x = 0; x < MAX_LEV_FIELDX; x++)
+  {
     for (y = 0; y < MAX_LEV_FIELDY; y++)
-      level->field[x][y] = EL_SAND;
+    {
+      if (add_border && (x == 0 || x == STD_LEV_FIELDX - 1 ||
+                        y == 0 || y == STD_LEV_FIELDY - 1))
+       level->field[x][y] = getEngineElement(EL_STEELWALL);
+      else
+       level->field[x][y] = getEngineElement(EL_SAND);
+    }
+  }
 
-  level->field[0][0] = EL_PLAYER_1;
-  level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
+  level->field[x1][y1] = getEngineElement(EL_PLAYER_1);
+  level->field[x2][y2] = getEngineElement(EL_EXIT_CLOSED);
 
-  BorderElement = EL_STEELWALL;
+  BorderElement = getEngineElement(EL_STEELWALL);
 
   // detect custom elements when loading them
   level->file_has_custom_elements = FALSE;
 
+  // set random colors for BD style levels according to preferred color type
+  SetRandomLevelColors_BD(setup.bd_default_color_type);
+
+  // set default color type and colors for BD style level colors
+  SetDefaultLevelColorType_BD();
+  SetDefaultLevelColors_BD();
+
   // set all bug compatibility flags to "false" => do not emulate this bug
   level->use_action_after_change_bug = FALSE;
 
@@ -1820,6 +2474,16 @@ static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
     int element = i;
     struct ElementInfo *ei = &element_info[element];
 
+    if (element == EL_MM_GRAY_BALL)
+    {
+      struct LevelInfo_MM *level_mm = level->native_mm_level;
+      int j;
+
+      for (j = 0; j < level->num_mm_ball_contents; j++)
+       level->mm_ball_content[j] =
+         map_element_MM_to_RND(level_mm->ball_content[j]);
+    }
+
     // never initialize clipboard elements after the very first time
     // (to be able to use clipboard elements between several levels)
     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
@@ -1849,8 +2513,7 @@ static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
     setElementChangeInfoToDefaults(ei->change);
 
     if (IS_CUSTOM_ELEMENT(element) ||
-       IS_GROUP_ELEMENT(element) ||
-       IS_INTERNAL_ELEMENT(element))
+       IS_GROUP_ELEMENT(element))
     {
       setElementDescriptionToDefault(ei);
 
@@ -1893,6 +2556,16 @@ static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
 
       *group = xx_group;
     }
+
+    if (IS_EMPTY_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      xx_ei = *ei;             // copy element data into temporary buffer
+
+      setConfigToDefaultsFromConfigList(chunk_config_EMPX);
+
+      *ei = xx_ei;
+    }
   }
 
   clipboard_elements_initialized = TRUE;
@@ -2002,6 +2675,32 @@ static void ActivateLevelTemplate(void)
   }
 }
 
+boolean isLevelsetFilename_BD(char *filename)
+{
+  return (strSuffixLower(filename, ".bd") ||
+         strSuffixLower(filename, ".bdr") ||
+         strSuffixLower(filename, ".brc") ||
+         strSuffixLower(filename, ".gds"));
+}
+
+static boolean checkForPackageFromBasename_BD(char *basename)
+{
+  // check for native BD level file extensions
+  if (!isLevelsetFilename_BD(basename))
+    return FALSE;
+
+  // check for standard single-level BD files (like "001.bd")
+  if (strSuffixLower(basename, ".bd") &&
+      strlen(basename) == 6 &&
+      basename[0] >= '0' && basename[0] <= '9' &&
+      basename[1] >= '0' && basename[1] <= '9' &&
+      basename[2] >= '0' && basename[2] <= '9')
+    return FALSE;
+
+  // this is a level package in native BD file format
+  return TRUE;
+}
+
 static char *getLevelFilenameFromBasename(char *basename)
 {
   static char *filename = NULL;
@@ -2036,6 +2735,10 @@ static int getFileTypeFromBasename(char *basename)
       strchr(basename, '%') == NULL)
     return LEVEL_FILE_TYPE_SB;
 
+  // check for typical filename of a Boulder Dash (GDash) level package file
+  if (checkForPackageFromBasename_BD(basename))
+    return LEVEL_FILE_TYPE_BD;
+
   // ---------- try to determine file type from filesize ----------
 
   checked_free(filename);
@@ -2295,6 +2998,11 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
   if (fileExists(lfi->filename))
     return;
 
+  // check for native Boulder Dash level file
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_BD, "%03d.bd", nr);
+  if (fileExists(lfi->filename))
+    return;
+
   // check for Emerald Mine level file (V1)
   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
                                       'a' + (nr / 10) % 26, '0' + nr % 10);
@@ -2814,9 +3522,10 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
       for (x = 0; x < 3; x++)
        ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
 
+    // bits 0 - 31 of "has_event[]"
     event_bits = getFile32BitBE(file);
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
-      if (event_bits & (1 << j))
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
+      if (event_bits & (1u << j))
        ei->change->has_event[j] = TRUE;
 
     ei->change->target_element = getMappedElement(getFile16BitBE(file));
@@ -2825,7 +3534,7 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
     ei->change->delay_random = getFile16BitBE(file);
     ei->change->delay_frames = getFile16BitBE(file);
 
-    ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
+    ei->change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
 
     ei->change->explode = getFile8Bit(file);
     ei->change->use_target_content = getFile8Bit(file);
@@ -2952,7 +3661,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
     // bits 0 - 31 of "has_event[]" ...
     event_bits = getFile32BitBE(file);
     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
-      if (event_bits & (1 << j))
+      if (event_bits & (1u << j))
        change->has_event[j] = TRUE;
 
     change->target_element = getMappedElement(getFile16BitBE(file));
@@ -2993,7 +3702,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
     // ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible)
     event_bits = getFile8Bit(file);
     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
-      if (event_bits & (1 << (j - 32)))
+      if (event_bits & (1u << (j - 32)))
        change->has_event[j] = TRUE;
   }
 
@@ -3322,6 +4031,10 @@ static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level)
 
   while (!checkEndOfFile(file))
   {
+    // level file might contain invalid change page number
+    if (xx_current_change_page >= ei->num_change_pages)
+      break;
+
     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
 
     xx_change = *change;       // copy change data into temporary buffer
@@ -3351,6 +4064,9 @@ static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
   struct ElementInfo *ei = &element_info[element];
   struct ElementGroupInfo *group = ei->group;
 
+  if (group == NULL)
+    return -1;
+
   xx_ei = *ei;         // copy element data into temporary buffer
   xx_group = *group;   // copy group data into temporary buffer
 
@@ -3371,6 +4087,30 @@ static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
   return real_chunk_size;
 }
 
+static int LoadLevel_EMPX(File *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int real_chunk_size = 2;
+  struct ElementInfo *ei = &element_info[element];
+
+  xx_ei = *ei;         // copy element data into temporary buffer
+
+  while (!checkEndOfFile(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_EMPX,
+                                           -1, element);
+
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  *ei = xx_ei;
+
+  level->file_has_custom_elements = TRUE;
+
+  return real_chunk_size;
+}
+
 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
                                      struct LevelFileInfo *level_file_info,
                                      boolean level_info_only)
@@ -3493,6 +4233,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "NOTE", -1,                    LoadLevel_NOTE },
       { "CUSX", -1,                    LoadLevel_CUSX },
       { "GRPX", -1,                    LoadLevel_GRPX },
+      { "EMPX", -1,                    LoadLevel_EMPX },
 
       {  NULL,  0,                     NULL }
     };
@@ -3526,6 +4267,14 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
        int chunk_size_expected =
          (chunk_info[i].loader)(file, chunk_size, level);
 
+       if (chunk_size_expected < 0)
+       {
+         Warn("error reading chunk '%s' in level file '%s'",
+              chunk_name, filename);
+
+         break;
+       }
+
        // the size of some chunks cannot be checked before reading other
        // chunks first (like "HEAD" and "BODY") that contain some header
        // information, so check them here
@@ -3533,6 +4282,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
        {
          Warn("wrong size (%d) of chunk '%s' in level file '%s'",
               chunk_size, chunk_name, filename);
+
+         break;
        }
       }
     }
@@ -3542,6 +4293,440 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
 }
 
 
+// ----------------------------------------------------------------------------
+// functions for loading BD level
+// ----------------------------------------------------------------------------
+
+#define LEVEL_TO_CAVE(e)       (map_element_RND_to_BD_cave(e))
+#define CAVE_TO_LEVEL(e)       (map_element_BD_to_RND_cave(e))
+
+static void CopyNativeLevel_RND_to_BD(struct LevelInfo *level)
+{
+  struct LevelInfo_BD *level_bd = level->native_bd_level;
+  GdCave *cave = NULL; // will be changed below
+  int cave_w = MIN(level->fieldx, MAX_PLAYFIELD_WIDTH);
+  int cave_h = MIN(level->fieldy, MAX_PLAYFIELD_HEIGHT);
+  int x, y;
+
+  setLevelInfoToDefaults_BD_Ext(cave_w, cave_h);
+
+  // cave and map newly allocated when set to defaults above
+  cave = level_bd->cave;
+
+  // level type
+  cave->intermission                   = level->bd_intermission;
+
+  // level settings
+  cave->level_time[0]                  = level->time;
+  cave->level_diamonds[0]              = level->gems_needed;
+
+  // game timing
+  cave->scheduling                     = level->bd_scheduling_type;
+  cave->pal_timing                     = level->bd_pal_timing;
+  cave->level_speed[0]                 = level->bd_cycle_delay_ms;
+  cave->level_ckdelay[0]               = level->bd_cycle_delay_c64;
+  cave->level_hatching_delay_frame[0]  = level->bd_hatching_delay_cycles;
+  cave->level_hatching_delay_time[0]   = level->bd_hatching_delay_seconds;
+
+  // scores
+  cave->level_timevalue[0]             = level->score[SC_TIME_BONUS];
+  cave->diamond_value                  = level->score[SC_EMERALD];
+  cave->extra_diamond_value            = level->score[SC_DIAMOND_EXTRA];
+
+  // compatibility settings
+  cave->lineshift                      = level->bd_line_shifting_borders;
+  cave->border_scan_first_and_last     = level->bd_scan_first_and_last_row;
+  cave->short_explosions               = level->bd_short_explosions;
+
+  // player properties
+  cave->diagonal_movements             = level->bd_diagonal_movements;
+  cave->active_is_first_found          = level->bd_topmost_player_active;
+  cave->pushing_stone_prob             = level->bd_pushing_prob            * 10000;
+  cave->pushing_stone_prob_sweet       = level->bd_pushing_prob_with_sweet * 10000;
+  cave->mega_stones_pushable_with_sweet        = level->bd_push_mega_rock_with_sweet;
+  cave->snap_element                   = LEVEL_TO_CAVE(level->bd_snap_element);
+
+  // element properties
+  cave->level_bonus_time[0]            = level->bd_clock_extra_time;
+  cave->voodoo_collects_diamonds       = level->bd_voodoo_collects_diamonds;
+  cave->voodoo_any_hurt_kills_player   = level->bd_voodoo_hurt_kills_player;
+  cave->voodoo_dies_by_stone           = level->bd_voodoo_dies_by_rock;
+  cave->voodoo_disappear_in_explosion  = level->bd_voodoo_vanish_by_explosion;
+  cave->level_penalty_time[0]          = level->bd_voodoo_penalty_time;
+  cave->level_magic_wall_time[0]       = level->bd_magic_wall_time;
+  cave->magic_timer_zero_is_infinite   = level->bd_magic_wall_zero_infinite;
+  cave->magic_timer_wait_for_hatching  = level->bd_magic_wall_wait_hatching;
+  cave->magic_wall_stops_amoeba                = level->bd_magic_wall_stops_amoeba;
+  cave->magic_wall_breakscan           = level->bd_magic_wall_break_scan;
+
+  cave->magic_diamond_to               = LEVEL_TO_CAVE(level->bd_magic_wall_diamond_to);
+  cave->magic_stone_to                 = LEVEL_TO_CAVE(level->bd_magic_wall_rock_to);
+  cave->magic_mega_stone_to            = LEVEL_TO_CAVE(level->bd_magic_wall_mega_rock_to);
+  cave->magic_nut_to                   = LEVEL_TO_CAVE(level->bd_magic_wall_nut_to);
+  cave->magic_nitro_pack_to            = LEVEL_TO_CAVE(level->bd_magic_wall_nitro_pack_to);
+  cave->magic_flying_diamond_to                = LEVEL_TO_CAVE(level->bd_magic_wall_flying_diamond_to);
+  cave->magic_flying_stone_to          = LEVEL_TO_CAVE(level->bd_magic_wall_flying_rock_to);
+
+  cave->amoeba_timer_wait_for_hatching = level->bd_amoeba_wait_for_hatching;
+  cave->amoeba_timer_started_immediately= level->bd_amoeba_start_immediately;
+  cave->amoeba_2_explodes_by_amoeba    = level->bd_amoeba_2_explode_by_amoeba;
+  cave->level_amoeba_threshold[0]      = level->bd_amoeba_1_threshold_too_big;
+  cave->level_amoeba_time[0]           = level->bd_amoeba_1_slow_growth_time;
+  cave->amoeba_growth_prob             = level->bd_amoeba_1_slow_growth_rate * 10000;
+  cave->amoeba_fast_growth_prob                = level->bd_amoeba_1_fast_growth_rate * 10000;
+  cave->level_amoeba_2_threshold[0]    = level->bd_amoeba_2_threshold_too_big;
+  cave->level_amoeba_2_time[0]         = level->bd_amoeba_2_slow_growth_time;
+  cave->amoeba_2_growth_prob           = level->bd_amoeba_2_slow_growth_rate * 10000;
+  cave->amoeba_2_fast_growth_prob      = level->bd_amoeba_2_fast_growth_rate * 10000;
+
+  cave->amoeba_too_big_effect          = LEVEL_TO_CAVE(level->bd_amoeba_1_content_too_big);
+  cave->amoeba_enclosed_effect         = LEVEL_TO_CAVE(level->bd_amoeba_1_content_enclosed);
+  cave->amoeba_2_too_big_effect                = LEVEL_TO_CAVE(level->bd_amoeba_2_content_too_big);
+  cave->amoeba_2_enclosed_effect       = LEVEL_TO_CAVE(level->bd_amoeba_2_content_enclosed);
+  cave->amoeba_2_explosion_effect      = LEVEL_TO_CAVE(level->bd_amoeba_2_content_exploding);
+  cave->amoeba_2_looks_like            = LEVEL_TO_CAVE(level->bd_amoeba_2_content_looks_like);
+
+  cave->slime_predictable              = level->bd_slime_is_predictable;
+  cave->slime_correct_random           = level->bd_slime_correct_random;
+  cave->level_slime_permeability[0]    = level->bd_slime_permeability_rate * 10000;
+  cave->level_slime_permeability_c64[0]        = level->bd_slime_permeability_bits_c64;
+  cave->level_slime_seed_c64[0]                = level->bd_slime_random_seed_c64;
+  cave->level_rand[0]                  = level->bd_cave_random_seed_c64;
+  cave->slime_eats_1                   = LEVEL_TO_CAVE(level->bd_slime_eats_element_1);
+  cave->slime_converts_1               = LEVEL_TO_CAVE(level->bd_slime_converts_to_element_1);
+  cave->slime_eats_2                   = LEVEL_TO_CAVE(level->bd_slime_eats_element_2);
+  cave->slime_converts_2               = LEVEL_TO_CAVE(level->bd_slime_converts_to_element_2);
+  cave->slime_eats_3                   = LEVEL_TO_CAVE(level->bd_slime_eats_element_3);
+  cave->slime_converts_3               = LEVEL_TO_CAVE(level->bd_slime_converts_to_element_3);
+
+  cave->acid_eats_this                 = LEVEL_TO_CAVE(level->bd_acid_eats_element);
+  cave->acid_spread_ratio              = level->bd_acid_spread_rate * 10000;
+  cave->acid_turns_to                  = LEVEL_TO_CAVE(level->bd_acid_turns_to_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->expanding_wall_changed         = level->bd_change_expanding_wall;
+
+  cave->replicators_active             = level->bd_replicators_active;
+  cave->replicator_delay_frame         = level->bd_replicator_create_delay;
+
+  cave->conveyor_belts_active          = level->bd_conveyor_belts_active;
+  cave->conveyor_belts_direction_changed= level->bd_conveyor_belts_changed;
+
+  cave->water_does_not_flow_down       = level->bd_water_cannot_flow_down;
+
+  cave->nut_turns_to_when_crushed      = LEVEL_TO_CAVE(level->bd_nut_content);
+
+  cave->pneumatic_hammer_frame         = level->bd_hammer_walls_break_delay;
+  cave->hammered_walls_reappear                = level->bd_hammer_walls_reappear;
+  cave->hammered_wall_reappear_frame   = level->bd_hammer_walls_reappear_delay;
+
+  cave->infinite_rockets               = level->bd_infinite_rockets;
+
+  cave->skeletons_needed_for_pot       = level->bd_num_skeletons_needed_for_pot;
+  cave->skeletons_worth_diamonds       = level->bd_skeleton_worth_num_diamonds;
+
+  cave->expanding_wall_looks_like      = LEVEL_TO_CAVE(level->bd_expanding_wall_looks_like);
+  cave->dirt_looks_like                        = LEVEL_TO_CAVE(level->bd_sand_looks_like);
+
+  cave->creatures_backwards                     = level->bd_creatures_start_backwards;
+  cave->creatures_direction_auto_change_on_start = level->bd_creatures_turn_on_hatching;
+  cave->creatures_direction_auto_change_time    = level->bd_creatures_auto_turn_delay;
+
+  cave->gravity                                = level->bd_gravity_direction;
+  cave->gravity_switch_active          = level->bd_gravity_switch_active;
+  cave->gravity_change_time            = level->bd_gravity_switch_delay;
+  cave->gravity_affects_all            = level->bd_gravity_affects_all;
+
+  cave->stone_falling_effect           = LEVEL_TO_CAVE(level->bd_rock_turns_to_on_falling);
+  cave->stone_bouncing_effect          = LEVEL_TO_CAVE(level->bd_rock_turns_to_on_impact);
+  cave->diamond_falling_effect         = LEVEL_TO_CAVE(level->bd_diamond_turns_to_on_falling);
+  cave->diamond_bouncing_effect                = LEVEL_TO_CAVE(level->bd_diamond_turns_to_on_impact);
+
+  cave->firefly_explode_to             = LEVEL_TO_CAVE(level->bd_firefly_1_explodes_to);
+  cave->alt_firefly_explode_to         = LEVEL_TO_CAVE(level->bd_firefly_2_explodes_to);
+  cave->butterfly_explode_to           = LEVEL_TO_CAVE(level->bd_butterfly_1_explodes_to);
+  cave->alt_butterfly_explode_to       = LEVEL_TO_CAVE(level->bd_butterfly_2_explodes_to);
+  cave->stonefly_explode_to            = LEVEL_TO_CAVE(level->bd_stonefly_explodes_to);
+  cave->dragonfly_explode_to           = LEVEL_TO_CAVE(level->bd_dragonfly_explodes_to);
+
+  cave->diamond_birth_effect           = LEVEL_TO_CAVE(level->bd_diamond_birth_turns_to);
+  cave->bomb_explosion_effect          = LEVEL_TO_CAVE(level->bd_bomb_explosion_turns_to);
+  cave->nitro_explosion_effect         = LEVEL_TO_CAVE(level->bd_nitro_explosion_turns_to);
+  cave->explosion_effect               = LEVEL_TO_CAVE(level->bd_explosion_turns_to);
+
+  cave->colorb                         = level->bd_color_b;
+  cave->color0                         = level->bd_color_0;
+  cave->color1                         = level->bd_color_1;
+  cave->color2                         = level->bd_color_2;
+  cave->color3                         = level->bd_color_3;
+  cave->color4                         = level->bd_color_4;
+  cave->color5                         = level->bd_color_5;
+
+  // level name
+  strncpy(cave->name, level->name, sizeof(GdString));
+  cave->name[sizeof(GdString) - 1] = '\0';
+
+  // playfield elements
+  for (x = 0; x < cave->w; x++)
+    for (y = 0; y < cave->h; y++)
+      cave->map[y][x] = LEVEL_TO_CAVE(level->field[x][y]);
+}
+
+static void CopyNativeLevel_BD_to_RND(struct LevelInfo *level)
+{
+  struct LevelInfo_BD *level_bd = level->native_bd_level;
+  GdCave *cave = level_bd->cave;
+  int bd_level_nr = level_bd->level_nr;
+  int x, y;
+
+  level->fieldx = MIN(cave->w, MAX_LEV_FIELDX);
+  level->fieldy = MIN(cave->h, MAX_LEV_FIELDY);
+
+  // level type
+  level->bd_intermission               = cave->intermission;
+
+  // level settings
+  level->time                          = cave->level_time[bd_level_nr];
+  level->gems_needed                   = cave->level_diamonds[bd_level_nr];
+
+  // game timing
+  level->bd_scheduling_type            = cave->scheduling;
+  level->bd_pal_timing                 = cave->pal_timing;
+  level->bd_cycle_delay_ms             = cave->level_speed[bd_level_nr];
+  level->bd_cycle_delay_c64            = cave->level_ckdelay[bd_level_nr];
+  level->bd_hatching_delay_cycles      = cave->level_hatching_delay_frame[bd_level_nr];
+  level->bd_hatching_delay_seconds     = cave->level_hatching_delay_time[bd_level_nr];
+
+  // scores
+  level->score[SC_TIME_BONUS]          = cave->level_timevalue[bd_level_nr];
+  level->score[SC_EMERALD]             = cave->diamond_value;
+  level->score[SC_DIAMOND_EXTRA]       = cave->extra_diamond_value;
+
+  // compatibility settings
+  level->bd_line_shifting_borders      = cave->lineshift;
+  level->bd_scan_first_and_last_row    = cave->border_scan_first_and_last;
+  level->bd_short_explosions           = cave->short_explosions;
+
+  // player properties
+  level->bd_diagonal_movements         = cave->diagonal_movements;
+  level->bd_topmost_player_active      = cave->active_is_first_found;
+  level->bd_pushing_prob               = cave->pushing_stone_prob       / 10000;
+  level->bd_pushing_prob_with_sweet    = cave->pushing_stone_prob_sweet / 10000;
+  level->bd_push_mega_rock_with_sweet  = cave->mega_stones_pushable_with_sweet;
+  level->bd_snap_element               = CAVE_TO_LEVEL(cave->snap_element);
+
+  // element properties
+  level->bd_clock_extra_time           = cave->level_bonus_time[bd_level_nr];
+  level->bd_voodoo_collects_diamonds   = cave->voodoo_collects_diamonds;
+  level->bd_voodoo_hurt_kills_player   = cave->voodoo_any_hurt_kills_player;
+  level->bd_voodoo_dies_by_rock                = cave->voodoo_dies_by_stone;
+  level->bd_voodoo_vanish_by_explosion = cave->voodoo_disappear_in_explosion;
+  level->bd_voodoo_penalty_time                = cave->level_penalty_time[bd_level_nr];
+  level->bd_magic_wall_time            = cave->level_magic_wall_time[bd_level_nr];
+  level->bd_magic_wall_zero_infinite   = cave->magic_timer_zero_is_infinite;
+  level->bd_magic_wall_wait_hatching   = cave->magic_timer_wait_for_hatching;
+  level->bd_magic_wall_stops_amoeba    = cave->magic_wall_stops_amoeba;
+  level->bd_magic_wall_break_scan      = cave->magic_wall_breakscan;
+
+  level->bd_magic_wall_diamond_to      = CAVE_TO_LEVEL(cave->magic_diamond_to);
+  level->bd_magic_wall_rock_to         = CAVE_TO_LEVEL(cave->magic_stone_to);
+  level->bd_magic_wall_mega_rock_to    = CAVE_TO_LEVEL(cave->magic_mega_stone_to);
+  level->bd_magic_wall_nut_to          = CAVE_TO_LEVEL(cave->magic_nut_to);
+  level->bd_magic_wall_nitro_pack_to   = CAVE_TO_LEVEL(cave->magic_nitro_pack_to);
+  level->bd_magic_wall_flying_diamond_to= CAVE_TO_LEVEL(cave->magic_flying_diamond_to);
+  level->bd_magic_wall_flying_rock_to  = CAVE_TO_LEVEL(cave->magic_flying_stone_to);
+
+  level->bd_amoeba_wait_for_hatching   = cave->amoeba_timer_wait_for_hatching;
+  level->bd_amoeba_start_immediately   = cave->amoeba_timer_started_immediately;
+  level->bd_amoeba_2_explode_by_amoeba = cave->amoeba_2_explodes_by_amoeba;
+  level->bd_amoeba_1_threshold_too_big = cave->level_amoeba_threshold[bd_level_nr];
+  level->bd_amoeba_1_slow_growth_time  = cave->level_amoeba_time[bd_level_nr];
+  level->bd_amoeba_1_slow_growth_rate  = cave->amoeba_growth_prob      / 10000;
+  level->bd_amoeba_1_fast_growth_rate  = cave->amoeba_fast_growth_prob / 10000;
+  level->bd_amoeba_2_threshold_too_big = cave->level_amoeba_2_threshold[bd_level_nr];
+  level->bd_amoeba_2_slow_growth_time  = cave->level_amoeba_2_time[bd_level_nr];
+  level->bd_amoeba_2_slow_growth_rate  = cave->amoeba_2_growth_prob      / 10000;
+  level->bd_amoeba_2_fast_growth_rate  = cave->amoeba_2_fast_growth_prob / 10000;
+
+  level->bd_amoeba_1_content_too_big   = CAVE_TO_LEVEL(cave->amoeba_too_big_effect);
+  level->bd_amoeba_1_content_enclosed  = CAVE_TO_LEVEL(cave->amoeba_enclosed_effect);
+  level->bd_amoeba_2_content_too_big   = CAVE_TO_LEVEL(cave->amoeba_2_too_big_effect);
+  level->bd_amoeba_2_content_enclosed  = CAVE_TO_LEVEL(cave->amoeba_2_enclosed_effect);
+  level->bd_amoeba_2_content_exploding = CAVE_TO_LEVEL(cave->amoeba_2_explosion_effect);
+  level->bd_amoeba_2_content_looks_like        = CAVE_TO_LEVEL(cave->amoeba_2_looks_like);
+
+  level->bd_slime_is_predictable       = cave->slime_predictable;
+  level->bd_slime_correct_random       = cave->slime_correct_random;
+  level->bd_slime_permeability_rate    = cave->level_slime_permeability[bd_level_nr] / 10000;
+  level->bd_slime_permeability_bits_c64        = cave->level_slime_permeability_c64[bd_level_nr];
+  level->bd_slime_random_seed_c64      = cave->level_slime_seed_c64[bd_level_nr];
+  level->bd_cave_random_seed_c64       = cave->level_rand[bd_level_nr];
+  level->bd_slime_eats_element_1       = CAVE_TO_LEVEL(cave->slime_eats_1);
+  level->bd_slime_converts_to_element_1        = CAVE_TO_LEVEL(cave->slime_converts_1);
+  level->bd_slime_eats_element_2       = CAVE_TO_LEVEL(cave->slime_eats_2);
+  level->bd_slime_converts_to_element_2        = CAVE_TO_LEVEL(cave->slime_converts_2);
+  level->bd_slime_eats_element_3       = CAVE_TO_LEVEL(cave->slime_eats_3);
+  level->bd_slime_converts_to_element_3        = CAVE_TO_LEVEL(cave->slime_converts_3);
+
+  level->bd_acid_eats_element          = CAVE_TO_LEVEL(cave->acid_eats_this);
+  level->bd_acid_spread_rate           = cave->acid_spread_ratio / 10000;
+  level->bd_acid_turns_to_element      = CAVE_TO_LEVEL(cave->acid_turns_to);
+
+  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_change_expanding_wall      = cave->expanding_wall_changed;
+
+  level->bd_replicators_active         = cave->replicators_active;
+  level->bd_replicator_create_delay    = cave->replicator_delay_frame;
+
+  level->bd_conveyor_belts_active      = cave->conveyor_belts_active;
+  level->bd_conveyor_belts_changed     = cave->conveyor_belts_direction_changed;
+
+  level->bd_water_cannot_flow_down     = cave->water_does_not_flow_down;
+
+  level->bd_nut_content                        = CAVE_TO_LEVEL(cave->nut_turns_to_when_crushed);
+
+  level->bd_hammer_walls_break_delay   = cave->pneumatic_hammer_frame;
+  level->bd_hammer_walls_reappear      = cave->hammered_walls_reappear;
+  level->bd_hammer_walls_reappear_delay        = cave->hammered_wall_reappear_frame;
+
+  level->bd_infinite_rockets           = cave->infinite_rockets;
+
+  level->bd_num_skeletons_needed_for_pot= cave->skeletons_needed_for_pot;
+  level->bd_skeleton_worth_num_diamonds        = cave->skeletons_worth_diamonds;
+
+  level->bd_expanding_wall_looks_like  = CAVE_TO_LEVEL(cave->expanding_wall_looks_like);
+  level->bd_sand_looks_like            = CAVE_TO_LEVEL(cave->dirt_looks_like);
+
+  level->bd_creatures_start_backwards  = cave->creatures_backwards;
+  level->bd_creatures_turn_on_hatching = cave->creatures_direction_auto_change_on_start;
+  level->bd_creatures_auto_turn_delay  = cave->creatures_direction_auto_change_time;
+
+  level->bd_gravity_direction          = cave->gravity;
+  level->bd_gravity_switch_active      = cave->gravity_switch_active;
+  level->bd_gravity_switch_delay       = cave->gravity_change_time;
+  level->bd_gravity_affects_all                = cave->gravity_affects_all;
+
+  level->bd_rock_turns_to_on_falling   = CAVE_TO_LEVEL(cave->stone_falling_effect);
+  level->bd_rock_turns_to_on_impact    = CAVE_TO_LEVEL(cave->stone_bouncing_effect);
+  level->bd_diamond_turns_to_on_falling        = CAVE_TO_LEVEL(cave->diamond_falling_effect);
+  level->bd_diamond_turns_to_on_impact = CAVE_TO_LEVEL(cave->diamond_bouncing_effect);
+
+  level->bd_firefly_1_explodes_to      = CAVE_TO_LEVEL(cave->firefly_explode_to);
+  level->bd_firefly_2_explodes_to      = CAVE_TO_LEVEL(cave->alt_firefly_explode_to);
+  level->bd_butterfly_1_explodes_to    = CAVE_TO_LEVEL(cave->butterfly_explode_to);
+  level->bd_butterfly_2_explodes_to    = CAVE_TO_LEVEL(cave->alt_butterfly_explode_to);
+  level->bd_stonefly_explodes_to       = CAVE_TO_LEVEL(cave->stonefly_explode_to);
+  level->bd_dragonfly_explodes_to      = CAVE_TO_LEVEL(cave->dragonfly_explode_to);
+
+  level->bd_diamond_birth_turns_to     = CAVE_TO_LEVEL(cave->diamond_birth_effect);
+  level->bd_bomb_explosion_turns_to    = CAVE_TO_LEVEL(cave->bomb_explosion_effect);
+  level->bd_nitro_explosion_turns_to   = CAVE_TO_LEVEL(cave->nitro_explosion_effect);
+  level->bd_explosion_turns_to         = CAVE_TO_LEVEL(cave->explosion_effect);
+
+  level->bd_color_b                    = cave->colorb;
+  level->bd_color_0                    = cave->color0;
+  level->bd_color_1                    = cave->color1;
+  level->bd_color_2                    = cave->color2;
+  level->bd_color_3                    = cave->color3;
+  level->bd_color_4                    = cave->color4;
+  level->bd_color_5                    = cave->color5;
+
+  // set default color type and colors for BD style level colors
+  SetDefaultLevelColorType_BD();
+  SetDefaultLevelColors_BD();
+
+  // level name
+  char *cave_name = getStringPrint("%s / %d", cave->name, bd_level_nr + 1);
+
+  strncpy(level->name, cave_name, MAX_LEVEL_NAME_LEN);
+  level->name[MAX_LEVEL_NAME_LEN] = '\0';
+
+  // playfield elements
+  for (x = 0; x < level->fieldx; x++)
+    for (y = 0; y < level->fieldy; y++)
+      level->field[x][y] = CAVE_TO_LEVEL(cave->map[y][x]);
+
+  checked_free(cave_name);
+}
+
+static void setTapeInfoToDefaults(void);
+
+static void CopyNativeTape_BD_to_RND(struct LevelInfo *level)
+{
+  struct LevelInfo_BD *level_bd = level->native_bd_level;
+  GdCave *cave = level_bd->cave;
+  GdReplay *replay = level_bd->replay;
+  int i;
+
+  if (replay == NULL)
+    return;
+
+  // always start with reliable default values
+  setTapeInfoToDefaults();
+
+  tape.level_nr = level_nr;            // (currently not used)
+  tape.random_seed = replay->seed;
+
+  TapeSetDateFromIsoDateString(replay->date);
+
+  tape.counter = 0;
+  tape.pos[tape.counter].delay = 0;
+
+  tape.bd_replay = TRUE;
+
+  // all time calculations only used to display approximate tape time
+  int cave_speed = cave->speed;
+  int milliseconds_game = 0;
+  int milliseconds_elapsed = 20;
+
+  for (i = 0; i < replay->movements->len; i++)
+  {
+    int replay_action = replay->movements->data[i];
+    int tape_action = map_action_BD_to_RND(replay_action);
+    byte action[MAX_TAPE_ACTIONS] = { tape_action };
+    boolean success = 0;
+
+    while (1)
+    {
+      success = TapeAddAction(action);
+
+      milliseconds_game += milliseconds_elapsed;
+
+      if (milliseconds_game >= cave_speed)
+      {
+       milliseconds_game -= cave_speed;
+
+       break;
+      }
+    }
+
+    tape.counter++;
+    tape.pos[tape.counter].delay = 0;
+    tape.pos[tape.counter].action[0] = 0;
+
+    if (!success)
+    {
+      Warn("BD replay truncated: size exceeds maximum tape size %d", MAX_TAPE_LEN);
+
+      break;
+    }
+  }
+
+  TapeHaltRecording();
+
+  if (!replay->success)
+    Warn("BD replay is marked as not successful");
+}
+
+
 // ----------------------------------------------------------------------------
 // functions for loading EM level
 // ----------------------------------------------------------------------------
@@ -3606,6 +4791,7 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   cav->lenses_time             = level->lenses_time;
   cav->magnify_time            = level->magnify_time;
 
+  cav->wind_time = 9999;
   cav->wind_direction =
     map_direction_RND_to_EM(level->wind_direction_initial);
 
@@ -3999,8 +5185,6 @@ static void CopyNativeTape_RND_to_SP(struct LevelInfo *level)
   demo->is_available = TRUE;
 }
 
-static void setTapeInfoToDefaults(void);
-
 static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
 {
   struct LevelInfo_SP *level_sp = level->native_sp_level;
@@ -4055,7 +5239,7 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
 static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level)
 {
   struct LevelInfo_MM *level_mm = level->native_mm_level;
-  int x, y;
+  int i, x, y;
 
   level_mm->fieldx = MIN(level->fieldx, MM_MAX_PLAYFIELD_WIDTH);
   level_mm->fieldy = MIN(level->fieldy, MM_MAX_PLAYFIELD_HEIGHT);
@@ -4064,9 +5248,13 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level)
   level_mm->kettles_needed = level->gems_needed;
   level_mm->auto_count_kettles = level->auto_count_gems;
 
-  level_mm->laser_red = level->mm_laser_red;
-  level_mm->laser_green = level->mm_laser_green;
-  level_mm->laser_blue = level->mm_laser_blue;
+  level_mm->mm_laser_red   = level->mm_laser_red;
+  level_mm->mm_laser_green = level->mm_laser_green;
+  level_mm->mm_laser_blue  = level->mm_laser_blue;
+
+  level_mm->df_laser_red   = level->df_laser_red;
+  level_mm->df_laser_green = level->df_laser_green;
+  level_mm->df_laser_blue  = level->df_laser_blue;
 
   strcpy(level_mm->name, level->name);
   strcpy(level_mm->author, level->author);
@@ -4083,6 +5271,15 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level)
   level_mm->time_ball    = level->mm_time_ball;
   level_mm->time_block   = level->mm_time_block;
 
+  level_mm->num_ball_contents = level->num_mm_ball_contents;
+  level_mm->ball_choice_mode = level->mm_ball_choice_mode;
+  level_mm->rotate_ball_content = level->rotate_mm_ball_content;
+  level_mm->explode_ball = level->explode_mm_ball;
+
+  for (i = 0; i < level->num_mm_ball_contents; i++)
+    level_mm->ball_content[i] =
+      map_element_RND_to_MM(level->mm_ball_content[i]);
+
   for (x = 0; x < level->fieldx; x++)
     for (y = 0; y < level->fieldy; y++)
       Ur[x][y] =
@@ -4092,7 +5289,7 @@ static void CopyNativeLevel_RND_to_MM(struct LevelInfo *level)
 static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level)
 {
   struct LevelInfo_MM *level_mm = level->native_mm_level;
-  int x, y;
+  int i, x, y;
 
   level->fieldx = MIN(level_mm->fieldx, MAX_LEV_FIELDX);
   level->fieldy = MIN(level_mm->fieldy, MAX_LEV_FIELDY);
@@ -4101,9 +5298,13 @@ static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level)
   level->gems_needed = level_mm->kettles_needed;
   level->auto_count_gems = level_mm->auto_count_kettles;
 
-  level->mm_laser_red = level_mm->laser_red;
-  level->mm_laser_green = level_mm->laser_green;
-  level->mm_laser_blue = level_mm->laser_blue;
+  level->mm_laser_red   = level_mm->mm_laser_red;
+  level->mm_laser_green = level_mm->mm_laser_green;
+  level->mm_laser_blue  = level_mm->mm_laser_blue;
+
+  level->df_laser_red   = level_mm->df_laser_red;
+  level->df_laser_green = level_mm->df_laser_green;
+  level->df_laser_blue  = level_mm->df_laser_blue;
 
   strcpy(level->name, level_mm->name);
 
@@ -4123,6 +5324,15 @@ static void CopyNativeLevel_MM_to_RND(struct LevelInfo *level)
   level->mm_time_ball  = level_mm->time_ball;
   level->mm_time_block = level_mm->time_block;
 
+  level->num_mm_ball_contents = level_mm->num_ball_contents;
+  level->mm_ball_choice_mode = level_mm->ball_choice_mode;
+  level->rotate_mm_ball_content = level_mm->rotate_ball_content;
+  level->explode_mm_ball = level_mm->explode_ball;
+
+  for (i = 0; i < level->num_mm_ball_contents; i++)
+    level->mm_ball_content[i] =
+      map_element_MM_to_RND(level_mm->ball_content[i]);
+
   for (x = 0; x < level->fieldx; x++)
     for (y = 0; y < level->fieldy; y++)
       level->field[x][y] = map_element_MM_to_RND(level_mm->field[x][y]);
@@ -5604,8 +6814,7 @@ static int getMappedElement_DC(int element)
   return getMappedElement(element);
 }
 
-static void LoadLevelFromFileStream_DC(File *file, struct LevelInfo *level,
-                                      int nr)
+static void LoadLevelFromFileStream_DC(File *file, struct LevelInfo *level)
 {
   byte header[DC_LEVEL_HEADER_SIZE];
   int envelope_size;
@@ -5854,7 +7063,7 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
     }
   }
 
-  LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
+  LoadLevelFromFileStream_DC(file, level);
 
   closeFile(file);
 }
@@ -5927,7 +7136,6 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
   boolean invalid_playfield_char = FALSE;
   boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces");
   int file_level_nr = 0;
-  int line_nr = 0;
   int x = 0, y = 0;            // initialized to make compilers happy
 
   last_comment[0] = '\0';
@@ -5969,10 +7177,6 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
     if (!getStringFromFile(file, line, MAX_LINE_LEN))
       break;
 
-    // check if line was completely read and is terminated by line break
-    if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
-      line_nr++;
-
     // cut trailing line break (this can be newline and/or carriage return)
     for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
       if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
@@ -6157,6 +7361,20 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
 // functions for handling native levels
 // -------------------------------------------------------------------------
 
+static void LoadLevelFromFileInfo_BD(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info,
+                                    boolean level_info_only)
+{
+  int pos = 0;
+
+  // determine position of requested level inside level package
+  if (level_file_info->packed)
+    pos = level_file_info->nr - leveldir_current->first_level;
+
+  if (!LoadNativeLevel_BD(level_file_info->filename, pos, level_info_only))
+    level->no_valid_file = TRUE;
+}
+
 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
                                     struct LevelFileInfo *level_file_info,
                                     boolean level_info_only)
@@ -6189,7 +7407,9 @@ static void LoadLevelFromFileInfo_MM(struct LevelInfo *level,
 
 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 {
-  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level->game_engine_type == GAME_ENGINE_TYPE_BD)
+    CopyNativeLevel_RND_to_BD(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
     CopyNativeLevel_RND_to_EM(level);
   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
     CopyNativeLevel_RND_to_SP(level);
@@ -6199,7 +7419,9 @@ void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 
 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 {
-  if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level->game_engine_type == GAME_ENGINE_TYPE_BD)
+    CopyNativeLevel_BD_to_RND(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
     CopyNativeLevel_EM_to_RND(level);
   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
     CopyNativeLevel_SP_to_RND(level);
@@ -6209,16 +7431,40 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 
 void SaveNativeLevel(struct LevelInfo *level)
 {
-  if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+  // saving native level files only supported for some game engines
+  if (level->game_engine_type != GAME_ENGINE_TYPE_BD &&
+      level->game_engine_type != GAME_ENGINE_TYPE_SP)
+    return;
+
+  char *file_ext = (level->game_engine_type == GAME_ENGINE_TYPE_BD ? "bd" :
+                   level->game_engine_type == GAME_ENGINE_TYPE_SP ? "sp" : "");
+  char *basename = getSingleLevelBasenameExt(level->file_info.nr, file_ext);
+  char *filename = getLevelFilenameFromBasename(basename);
+
+  if (fileExists(filename) && !Request("Native level file already exists! Overwrite it?", REQ_ASK))
+    return;
+
+  boolean success = FALSE;
+
+  if (level->game_engine_type == GAME_ENGINE_TYPE_BD)
   {
-    char *basename = getSingleLevelBasenameExt(level->file_info.nr, "sp");
-    char *filename = getLevelFilenameFromBasename(basename);
+    CopyNativeLevel_RND_to_BD(level);
+    // CopyNativeTape_RND_to_BD(level);
 
+    success = SaveNativeLevel_BD(filename);
+  }
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
     CopyNativeLevel_RND_to_SP(level);
     CopyNativeTape_RND_to_SP(level);
 
-    SaveNativeLevel_SP(filename);
+    success = SaveNativeLevel_SP(filename);
   }
+
+  if (success)
+    Request("Native level file saved!", REQ_CONFIRM);
+  else
+    Request("Failed to save native level file!", REQ_CONFIRM);
 }
 
 
@@ -6239,6 +7485,11 @@ static void LoadLevelFromFileInfo(struct LevelInfo *level,
       LoadLevelFromFileInfo_RND(level, level_file_info, level_info_only);
       break;
 
+    case LEVEL_FILE_TYPE_BD:
+      LoadLevelFromFileInfo_BD(level, level_file_info, level_info_only);
+      level->game_engine_type = GAME_ENGINE_TYPE_BD;
+      break;
+
     case LEVEL_FILE_TYPE_EM:
       LoadLevelFromFileInfo_EM(level, level_file_info, level_info_only);
       level->game_engine_type = GAME_ENGINE_TYPE_EM;
@@ -6271,6 +7522,9 @@ static void LoadLevelFromFileInfo(struct LevelInfo *level,
   if (level->no_valid_file)
     setLevelInfoToDefaults(level, level_info_only, FALSE);
 
+  if (check_special_flags("use_native_bd_game_engine"))
+    level->game_engine_type = GAME_ENGINE_TYPE_BD;
+
   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
     level->game_engine_type = GAME_ENGINE_TYPE_RND;
 
@@ -6508,6 +7762,13 @@ static void LoadLevel_InitSettings(struct LevelInfo *level)
 {
   // adjust level settings for (non-native) Sokoban-style levels
   LoadLevel_InitSettings_SB(level);
+
+  // rename levels with title "nameless level" or if renaming is forced
+  if (leveldir_current->empty_level_name != NULL &&
+      (strEqual(level->name, NAMELESS_LEVEL_NAME) ||
+       leveldir_current->force_level_name))
+    snprintf(level->name, MAX_LEVEL_NAME_LEN + 1,
+            leveldir_current->empty_level_name, level_nr);
 }
 
 static void LoadLevel_InitStandardElements(struct LevelInfo *level)
@@ -7246,7 +8507,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     event_bits = 0;
     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (change->has_event[j])
-       event_bits |= (1 << j);
+       event_bits |= (1u << j);
     putFile32BitBE(file, event_bits);
 
     putFile16BitBE(file, change->target_element);
@@ -7286,7 +8547,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     event_bits = 0;
     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
       if (change->has_event[j])
-       event_bits |= (1 << (j - 32));
+       event_bits |= (1u << (j - 32));
     putFile8Bit(file, event_bits);
   }
 }
@@ -7537,6 +8798,22 @@ static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
   return chunk_size;
 }
 
+static int SaveLevel_EMPX(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  int chunk_size = 0;
+  int i;
+
+  chunk_size += putFile16BitBE(file, element);
+
+  xx_ei = *ei;         // copy element data into temporary buffer
+
+  for (i = 0; chunk_config_EMPX[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_EMPX[i], FALSE);
+
+  return chunk_size;
+}
+
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename,
                                  boolean save_as_template)
 {
@@ -7628,6 +8905,18 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename,
        SaveLevel_GRPX(file, level, element);
       }
     }
+
+    for (i = 0; i < NUM_EMPTY_ELEMENTS_ALL; i++)
+    {
+      int element = GET_EMPTY_ELEMENT(i);
+
+      chunk_size = SaveLevel_EMPX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_EMPX_UNCHANGED)     // save if changed
+      {
+       putFileChunkBE(file, "EMPX", chunk_size);
+       SaveLevel_EMPX(file, level, element);
+      }
+    }
   }
 
   fclose(file);
@@ -7705,6 +8994,28 @@ void DumpLevel(struct LevelInfo *level)
   Print("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
   Print("rate time over score: %s\n", (level->rate_time_over_score ? "yes" : "no"));
 
+  if (options.debug)
+  {
+    int i, j;
+
+    for (i = 0; i < NUM_ENVELOPES; i++)
+    {
+      char *text = level->envelope[i].text;
+      int text_len = strlen(text);
+      boolean has_text = FALSE;
+
+      for (j = 0; j < text_len; j++)
+       if (text[j] != ' ' && text[j] != '\n')
+         has_text = TRUE;
+
+      if (has_text)
+      {
+       Print("\n");
+       Print("Envelope %d:\n'%s'\n", i + 1, text);
+      }
+    }
+  }
+
   PrintLine("-", 79);
 }
 
@@ -7730,6 +9041,46 @@ void DumpLevels(void)
   CloseAllAndExit(0);
 }
 
+void DumpLevelsetFromFilename_BD(char *filename)
+{
+  if (leveldir_current == NULL)        // no levelsets loaded yet
+    bd_open_all();
+
+  if (!LoadNativeLevel_BD(filename, 0, FALSE))
+    CloseAllAndExit(0);                // function has already printed warning
+
+  PrintLine("-", 79);
+  Print("Levelset '%s'\n", filename);
+  PrintLine("-", 79);
+
+  DumpLevelset_BD();
+
+  PrintLine("-", 79);
+
+  CloseAllAndExit(0);
+}
+
+void DumpLevelset(void)
+{
+  static LevelDirTree *dumplevelset_leveldir = NULL;
+
+  dumplevelset_leveldir = getTreeInfoFromIdentifier(leveldir_first,
+                                                    global.dumplevelset_leveldir);
+  if (dumplevelset_leveldir == NULL)
+    Fail("no such level identifier: '%s'", global.dumplevelset_leveldir);
+
+  PrintLine("-", 79);
+  Print("Levelset '%s'\n", dumplevelset_leveldir->identifier);
+  PrintLine("-", 79);
+
+  Print("Number of levels:   %d\n", dumplevelset_leveldir->levels);
+  Print("First level number: %d\n", dumplevelset_leveldir->first_level);
+
+  PrintLine("-", 79);
+
+  CloseAllAndExit(0);
+}
+
 
 // ============================================================================
 // tape file functions
@@ -7755,6 +9106,7 @@ static void setTapeInfoToDefaults(void)
   tape.level_nr = level_nr;
   tape.counter = 0;
   tape.changed = FALSE;
+  tape.solved = FALSE;
 
   tape.recording = FALSE;
   tape.playing = FALSE;
@@ -7841,8 +9193,7 @@ static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape)
     setTapeActionFlags(tape, getFile8Bit(file));
 
     tape->property_bits = getFile8Bit(file);
-
-    ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
+    tape->solved = getFile8Bit(file);
 
     engine_version = getFileVersion(file);
     if (engine_version > 0)
@@ -7944,7 +9295,7 @@ static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape)
       byte action = tape->pos[i].action[0];
       int k, num_moves = 0;
 
-      for (k = 0; k<4; k++)
+      for (k = 0; k < 4; k++)
       {
        if (action & joy_dir[k])
        {
@@ -8234,10 +9585,29 @@ void LoadSolutionTape(int nr)
 
   LoadTapeFromFilename(filename);
 
-  if (TAPE_IS_EMPTY(tape) &&
-      level.game_engine_type == GAME_ENGINE_TYPE_SP &&
-      level.native_sp_level->demo.is_available)
-    CopyNativeTape_SP_to_RND(&level);
+  if (TAPE_IS_EMPTY(tape))
+  {
+    if (level.game_engine_type == GAME_ENGINE_TYPE_BD &&
+       level.native_bd_level->replay != NULL)
+      CopyNativeTape_BD_to_RND(&level);
+    else if (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
+       level.native_sp_level->demo.is_available)
+      CopyNativeTape_SP_to_RND(&level);
+  }
+}
+
+void LoadScoreTape(char *score_tape_basename, int nr)
+{
+  char *filename = getScoreTapeFilename(score_tape_basename, nr);
+
+  LoadTapeFromFilename(filename);
+}
+
+void LoadScoreCacheTape(char *score_tape_basename, int nr)
+{
+  char *filename = getScoreCacheTapeFilename(score_tape_basename, nr);
+
+  LoadTapeFromFilename(filename);
 }
 
 static boolean checkSaveTape_SCRN(struct TapeInfo *tape)
@@ -8273,9 +9643,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile8Bit(file, getTapeActionValue(tape));
 
   putFile8Bit(file, tape->property_bits);
-
-  // unused bytes not at the end here for 4-byte alignment of engine_version
-  WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
+  putFile8Bit(file, tape->solved);
 
   putFileVersion(file, tape->engine_version);
 }
@@ -8401,7 +9769,7 @@ void SaveScoreTape(int nr)
   char *filename = getScoreTapeFilename(tape.score_tape_basename, nr);
 
   // used instead of "leveldir_current->subdir" (for network games)
-  InitScoreDirectory(levelset.identifier);
+  InitScoreTapeDirectory(levelset.identifier, nr);
 
   SaveTapeExt(filename);
 }
@@ -8457,6 +9825,10 @@ void DumpTape(struct TapeInfo *tape)
        tape->engine_version);
   Print("Level series identifier: '%s'\n", tape->level_identifier);
 
+  Print("Solution tape: %s\n",
+       tape->solved ? "yes" :
+       tape->game_version < VERSION_IDENT(4,3,2,3) ? "unknown" : "no");
+
   Print("Special tape properties: ");
   if (tape->property_bits == TAPE_PROPERTY_NONE)
     Print("[none]");
@@ -8565,6 +9937,13 @@ static void setScoreInfoToDefaultsExt(struct ScoreInfo *scores)
     strcpy(scores->entry[i].name, EMPTY_PLAYER_NAME);
     scores->entry[i].score = 0;
     scores->entry[i].time = 0;
+
+    scores->entry[i].id = -1;
+    strcpy(scores->entry[i].tape_date,    UNKNOWN_NAME);
+    strcpy(scores->entry[i].platform,     UNKNOWN_NAME);
+    strcpy(scores->entry[i].version,      UNKNOWN_NAME);
+    strcpy(scores->entry[i].country_name, UNKNOWN_NAME);
+    strcpy(scores->entry[i].country_code, "??");
   }
 
   scores->num_entries = 0;
@@ -8573,7 +9952,15 @@ static void setScoreInfoToDefaultsExt(struct ScoreInfo *scores)
 
   scores->updated = FALSE;
   scores->uploaded = FALSE;
+  scores->tape_downloaded = FALSE;
   scores->force_last_added = FALSE;
+
+  // The following values are intentionally not reset here:
+  // - last_level_nr
+  // - last_entry_nr
+  // - next_level_nr
+  // - continue_playing
+  // - continue_on_return
 }
 
 static void setScoreInfoToDefaults(void)
@@ -8720,6 +10107,18 @@ static int LoadScore_SCOR(File *file, int chunk_size, struct ScoreInfo *scores)
   return chunk_size;
 }
 
+static int LoadScore_SC4R(File *file, int chunk_size, struct ScoreInfo *scores)
+{
+  int i;
+
+  for (i = 0; i < scores->num_entries; i++)
+    scores->entry[i].score = getFile32BitBE(file);
+
+  chunk_size = scores->num_entries * 4;
+
+  return chunk_size;
+}
+
 static int LoadScore_TIME(File *file, int chunk_size, struct ScoreInfo *scores)
 {
   int i;
@@ -8821,6 +10220,7 @@ void LoadScore(int nr)
       { "INFO", -1,                    LoadScore_INFO },
       { "NAME", -1,                    LoadScore_NAME },
       { "SCOR", -1,                    LoadScore_SCOR },
+      { "SC4R", -1,                    LoadScore_SC4R },
       { "TIME", -1,                    LoadScore_TIME },
       { "TAPE", -1,                    LoadScore_TAPE },
 
@@ -8840,870 +10240,343 @@ void LoadScore(int nr)
        Warn("unknown chunk '%s' in score file '%s'",
              chunk_name, filename);
 
-       ReadUnusedBytesFromFile(file, chunk_size);
-      }
-      else if (chunk_info[i].size != -1 &&
-              chunk_info[i].size != chunk_size)
-      {
-       Warn("wrong size (%d) of chunk '%s' in score file '%s'",
-             chunk_size, chunk_name, filename);
-
-       ReadUnusedBytesFromFile(file, chunk_size);
-      }
-      else
-      {
-       // call function to load this score chunk
-       int chunk_size_expected =
-         (chunk_info[i].loader)(file, chunk_size, &scores);
-
-       // the size of some chunks cannot be checked before reading other
-       // chunks first (like "HEAD" and "BODY") that contain some header
-       // information, so check them here
-       if (chunk_size_expected != chunk_size)
-       {
-         Warn("wrong size (%d) of chunk '%s' in score file '%s'",
-               chunk_size, chunk_name, filename);
-       }
-      }
-    }
-  }
-
-  closeFile(file);
-}
-
-#if ENABLE_HISTORIC_CHUNKS
-void SaveScore_OLD(int nr)
-{
-  int i;
-  char *filename = getScoreFilename(nr);
-  FILE *file;
-
-  // used instead of "leveldir_current->subdir" (for network games)
-  InitScoreDirectory(levelset.identifier);
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Warn("cannot save score for level %d", nr);
-
-    return;
-  }
-
-  fprintf(file, "%s\n\n", SCORE_COOKIE);
-
-  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
-    fprintf(file, "%d %s\n", scores.entry[i].score, scores.entry[i].name);
-
-  fclose(file);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
-#endif
-
-static void SaveScore_VERS(FILE *file, struct ScoreInfo *scores)
-{
-  putFileVersion(file, scores->file_version);
-  putFileVersion(file, scores->game_version);
-}
-
-static void SaveScore_INFO(FILE *file, struct ScoreInfo *scores)
-{
-  int level_identifier_size = strlen(scores->level_identifier) + 1;
-  int i;
-
-  putFile16BitBE(file, level_identifier_size);
-
-  for (i = 0; i < level_identifier_size; i++)
-    putFile8Bit(file, scores->level_identifier[i]);
-
-  putFile16BitBE(file, scores->level_nr);
-  putFile16BitBE(file, scores->num_entries);
-}
-
-static void SaveScore_NAME(FILE *file, struct ScoreInfo *scores)
-{
-  int i, j;
-
-  for (i = 0; i < scores->num_entries; i++)
-  {
-    int name_size = strlen(scores->entry[i].name);
-
-    for (j = 0; j < MAX_PLAYER_NAME_LEN; j++)
-      putFile8Bit(file, (j < name_size ? scores->entry[i].name[j] : 0));
-  }
-}
-
-static void SaveScore_SCOR(FILE *file, struct ScoreInfo *scores)
-{
-  int i;
-
-  for (i = 0; i < scores->num_entries; i++)
-    putFile16BitBE(file, scores->entry[i].score);
-}
-
-static void SaveScore_TIME(FILE *file, struct ScoreInfo *scores)
-{
-  int i;
-
-  for (i = 0; i < scores->num_entries; i++)
-    putFile32BitBE(file, scores->entry[i].time);
-}
-
-static void SaveScore_TAPE(FILE *file, struct ScoreInfo *scores)
-{
-  int i, j;
-
-  for (i = 0; i < scores->num_entries; i++)
-  {
-    int size = strlen(scores->entry[i].tape_basename);
-
-    for (j = 0; j < MAX_SCORE_TAPE_BASENAME_LEN; j++)
-      putFile8Bit(file, (j < size ? scores->entry[i].tape_basename[j] : 0));
-  }
-}
-
-static void SaveScoreToFilename(char *filename)
-{
-  FILE *file;
-  int info_chunk_size;
-  int name_chunk_size;
-  int scor_chunk_size;
-  int time_chunk_size;
-  int tape_chunk_size;
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Warn("cannot save score file '%s'", filename);
-
-    return;
-  }
-
-  info_chunk_size = 2 + (strlen(scores.level_identifier) + 1) + 2 + 2;
-  name_chunk_size = scores.num_entries * MAX_PLAYER_NAME_LEN;
-  scor_chunk_size = scores.num_entries * 2;
-  time_chunk_size = scores.num_entries * 4;
-  tape_chunk_size = scores.num_entries * MAX_SCORE_TAPE_BASENAME_LEN;
-
-  putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
-  putFileChunkBE(file, "SCOR", CHUNK_SIZE_NONE);
-
-  putFileChunkBE(file, "VERS", SCORE_CHUNK_VERS_SIZE);
-  SaveScore_VERS(file, &scores);
-
-  putFileChunkBE(file, "INFO", info_chunk_size);
-  SaveScore_INFO(file, &scores);
-
-  putFileChunkBE(file, "NAME", name_chunk_size);
-  SaveScore_NAME(file, &scores);
-
-  putFileChunkBE(file, "SCOR", scor_chunk_size);
-  SaveScore_SCOR(file, &scores);
-
-  putFileChunkBE(file, "TIME", time_chunk_size);
-  SaveScore_TIME(file, &scores);
-
-  putFileChunkBE(file, "TAPE", tape_chunk_size);
-  SaveScore_TAPE(file, &scores);
-
-  fclose(file);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-void SaveScore(int nr)
-{
-  char *filename = getScoreFilename(nr);
-  int i;
-
-  // used instead of "leveldir_current->subdir" (for network games)
-  InitScoreDirectory(levelset.identifier);
-
-  scores.file_version = FILE_VERSION_ACTUAL;
-  scores.game_version = GAME_VERSION_ACTUAL;
-
-  strncpy(scores.level_identifier, levelset.identifier, MAX_FILENAME_LEN);
-  scores.level_identifier[MAX_FILENAME_LEN] = '\0';
-  scores.level_nr = level_nr;
-
-  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
-    if (scores.entry[i].score == 0 &&
-        scores.entry[i].time == 0 &&
-        strEqual(scores.entry[i].name, EMPTY_PLAYER_NAME))
-      break;
-
-  scores.num_entries = i;
-
-  if (scores.num_entries == 0)
-    return;
-
-  SaveScoreToFilename(filename);
-}
-
-void ExecuteAsThread(SDL_ThreadFunction function, char *name, void *data,
-                    char *error)
-{
-#if defined(PLATFORM_EMSCRIPTEN)
-  // threads currently not fully supported by Emscripten/SDL and some browsers
-  function(data);
-#else
-  SDL_Thread *thread = SDL_CreateThread(function, name, data);
-
-  if (thread != NULL)
-    SDL_DetachThread(thread);
-  else
-    Error("Cannot create thread to %s!", error);
-
-  // nasty kludge to lower probability of intermingled thread error messages
-  Delay(1);
-#endif
-}
-
-char *getPasswordJSON(char *password)
-{
-  static char password_json[MAX_FILENAME_LEN] = "";
-  static boolean initialized = FALSE;
-
-  if (!initialized)
-  {
-    if (password != NULL &&
-       !strEqual(password, "") &&
-       !strEqual(password, UNDEFINED_PASSWORD))
-      snprintf(password_json, MAX_FILENAME_LEN,
-              "  \"password\":             \"%s\",\n",
-              setup.api_server_password);
-
-    initialized = TRUE;
-  }
-
-  return password_json;
-}
-
-struct ApiGetScoreThreadData
-{
-  int level_nr;
-  char *score_cache_filename;
-};
-
-static void *CreateThreadData_ApiGetScore(int nr)
-{
-  struct ApiGetScoreThreadData *data =
-    checked_malloc(sizeof(struct ApiGetScoreThreadData));
-  char *score_cache_filename = getScoreCacheFilename(nr);
-
-  data->level_nr = nr;
-  data->score_cache_filename = getStringCopy(score_cache_filename);
-
-  return data;
-}
-
-static void FreeThreadData_ApiGetScore(void *data_raw)
-{
-  struct ApiGetScoreThreadData *data = data_raw;
-
-  checked_free(data->score_cache_filename);
-  checked_free(data);
-}
-
-static boolean SetRequest_ApiGetScore(struct HttpRequest *request,
-                                     void *data_raw)
-{
-  struct ApiGetScoreThreadData *data = data_raw;
-  int level_nr = data->level_nr;
-
-  request->hostname = setup.api_server_hostname;
-  request->port     = API_SERVER_PORT;
-  request->method   = API_SERVER_METHOD;
-  request->uri      = API_SERVER_URI_GET;
-
-  char *levelset_identifier = getEscapedJSON(leveldir_current->identifier);
-  char *levelset_name       = getEscapedJSON(leveldir_current->name);
-
-  snprintf(request->body, MAX_HTTP_BODY_SIZE,
-          "{\n"
-          "%s"
-          "  \"game_version\":         \"%s\",\n"
-          "  \"game_platform\":        \"%s\",\n"
-          "  \"levelset_identifier\":  \"%s\",\n"
-          "  \"levelset_name\":        \"%s\",\n"
-          "  \"level_nr\":             \"%d\"\n"
-          "}\n",
-          getPasswordJSON(setup.api_server_password),
-          getProgramRealVersionString(),
-          getProgramPlatformString(),
-          levelset_identifier,
-          levelset_name,
-          level_nr);
+       ReadUnusedBytesFromFile(file, chunk_size);
+      }
+      else if (chunk_info[i].size != -1 &&
+              chunk_info[i].size != chunk_size)
+      {
+       Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+             chunk_size, chunk_name, filename);
 
-  checked_free(levelset_identifier);
-  checked_free(levelset_name);
+       ReadUnusedBytesFromFile(file, chunk_size);
+      }
+      else
+      {
+       // call function to load this score chunk
+       int chunk_size_expected =
+         (chunk_info[i].loader)(file, chunk_size, &scores);
 
-  ConvertHttpRequestBodyToServerEncoding(request);
+       // the size of some chunks cannot be checked before reading other
+       // chunks first (like "HEAD" and "BODY") that contain some header
+       // information, so check them here
+       if (chunk_size_expected != chunk_size)
+       {
+         Warn("wrong size (%d) of chunk '%s' in score file '%s'",
+               chunk_size, chunk_name, filename);
+       }
+      }
+    }
+  }
 
-  return TRUE;
+  closeFile(file);
 }
 
-static void HandleResponse_ApiGetScore(struct HttpResponse *response,
-                                      void *data_raw)
+#if ENABLE_HISTORIC_CHUNKS
+void SaveScore_OLD(int nr)
 {
-  struct ApiGetScoreThreadData *data = data_raw;
-
-  if (response->body_size == 0)
-  {
-    // no scores available for this level
-
-    return;
-  }
-
-  ConvertHttpResponseBodyToClientEncoding(response);
-
-  char *filename = data->score_cache_filename;
-  FILE *file;
   int i;
+  char *filename = getScoreFilename(nr);
+  FILE *file;
 
   // used instead of "leveldir_current->subdir" (for network games)
-  InitScoreCacheDirectory(levelset.identifier);
+  InitScoreDirectory(levelset.identifier);
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
-    Warn("cannot save score cache file '%s'", filename);
+    Warn("cannot save score for level %d", nr);
 
     return;
   }
 
-  for (i = 0; i < response->body_size; i++)
-    fputc(response->body[i], file);
+  fprintf(file, "%s\n\n", SCORE_COOKIE);
+
+  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+    fprintf(file, "%d %s\n", scores.entry[i].score, scores.entry[i].name);
 
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
-
-  server_scores.updated = TRUE;
-}
-
-#if defined(PLATFORM_EMSCRIPTEN)
-static void Emscripten_ApiGetScore_Loaded(unsigned handle, void *data_raw,
-                                         void *buffer, unsigned int size)
-{
-  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
-
-  if (response != NULL)
-  {
-    HandleResponse_ApiGetScore(response, data_raw);
-
-    checked_free(response);
-  }
-  else
-  {
-    Error("server response too large to handle (%d bytes)", size);
-  }
-
-  FreeThreadData_ApiGetScore(data_raw);
 }
+#endif
 
-static void Emscripten_ApiGetScore_Failed(unsigned handle, void *data_raw,
-                                         int code, const char *status)
+static void SaveScore_VERS(FILE *file, struct ScoreInfo *scores)
 {
-  Error("server failed to handle request: %d %s", code, status);
-
-  FreeThreadData_ApiGetScore(data_raw);
+  putFileVersion(file, scores->file_version);
+  putFileVersion(file, scores->game_version);
 }
 
-static void Emscripten_ApiGetScore_Progress(unsigned handle, void *data_raw,
-                                           int bytes, int size)
+static void SaveScore_INFO(FILE *file, struct ScoreInfo *scores)
 {
-  // nothing to do here
-}
+  int level_identifier_size = strlen(scores->level_identifier) + 1;
+  int i;
 
-static void Emscripten_ApiGetScore_HttpRequest(struct HttpRequest *request,
-                                              void *data_raw)
-{
-  if (!SetRequest_ApiGetScore(request, data_raw))
-  {
-    FreeThreadData_ApiGetScore(data_raw);
+  putFile16BitBE(file, level_identifier_size);
 
-    return;
-  }
+  for (i = 0; i < level_identifier_size; i++)
+    putFile8Bit(file, scores->level_identifier[i]);
 
-  emscripten_async_wget2_data(request->uri,
-                             request->method,
-                             request->body,
-                             data_raw,
-                             TRUE,
-                             Emscripten_ApiGetScore_Loaded,
-                             Emscripten_ApiGetScore_Failed,
-                             Emscripten_ApiGetScore_Progress);
+  putFile16BitBE(file, scores->level_nr);
+  putFile16BitBE(file, scores->num_entries);
 }
 
-#else
-
-static void ApiGetScore_HttpRequestExt(struct HttpRequest *request,
-                                      struct HttpResponse *response,
-                                      void *data_raw)
+static void SaveScore_NAME(FILE *file, struct ScoreInfo *scores)
 {
-  if (!SetRequest_ApiGetScore(request, data_raw))
-    return;
-
-  if (!DoHttpRequest(request, response))
-  {
-    Error("HTTP request failed: %s", GetHttpError());
-
-    return;
-  }
+  int i, j;
 
-  if (!HTTP_SUCCESS(response->status_code))
+  for (i = 0; i < scores->num_entries; i++)
   {
-    // do not show error message if no scores found for this level set
-    if (response->status_code == 404)
-      return;
-
-    Error("server failed to handle request: %d %s",
-         response->status_code,
-         response->status_text);
+    int name_size = strlen(scores->entry[i].name);
 
-    return;
+    for (j = 0; j < MAX_PLAYER_NAME_LEN; j++)
+      putFile8Bit(file, (j < name_size ? scores->entry[i].name[j] : 0));
   }
-
-  HandleResponse_ApiGetScore(response, data_raw);
 }
 
-static void ApiGetScore_HttpRequest(struct HttpRequest *request,
-                                   struct HttpResponse *response,
-                                   void *data_raw)
+static void SaveScore_SCOR(FILE *file, struct ScoreInfo *scores)
 {
-  ApiGetScore_HttpRequestExt(request, response, data_raw);
+  int i;
 
-  FreeThreadData_ApiGetScore(data_raw);
+  for (i = 0; i < scores->num_entries; i++)
+    putFile16BitBE(file, scores->entry[i].score);
 }
-#endif
 
-static int ApiGetScoreThread(void *data_raw)
+static void SaveScore_SC4R(FILE *file, struct ScoreInfo *scores)
 {
-  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
-  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
-
-#if defined(PLATFORM_EMSCRIPTEN)
-  Emscripten_ApiGetScore_HttpRequest(request, data_raw);
-#else
-  ApiGetScore_HttpRequest(request, response, data_raw);
-#endif
-
-  checked_free(request);
-  checked_free(response);
+  int i;
 
-  return 0;
+  for (i = 0; i < scores->num_entries; i++)
+    putFile32BitBE(file, scores->entry[i].score);
 }
 
-static void ApiGetScoreAsThread(int nr)
+static void SaveScore_TIME(FILE *file, struct ScoreInfo *scores)
 {
-  struct ApiGetScoreThreadData *data = CreateThreadData_ApiGetScore(nr);
+  int i;
 
-  ExecuteAsThread(ApiGetScoreThread,
-                 "ApiGetScore", data,
-                 "download scores from server");
+  for (i = 0; i < scores->num_entries; i++)
+    putFile32BitBE(file, scores->entry[i].time);
 }
 
-static void LoadServerScoreFromCache(int nr)
+static void SaveScore_TAPE(FILE *file, struct ScoreInfo *scores)
 {
-  struct ScoreEntry score_entry;
-  struct
-  {
-    void *value;
-    boolean is_string;
-    int string_size;
-  }
-  score_mapping[] =
-  {
-    { &score_entry.score,              FALSE,  0                       },
-    { &score_entry.time,               FALSE,  0                       },
-    { score_entry.name,                        TRUE,   MAX_PLAYER_NAME_LEN     },
-    { score_entry.tape_basename,       TRUE,   MAX_FILENAME_LEN        },
-
-    { NULL,                            FALSE,  0                       }
-  };
-  char *filename = getScoreCacheFilename(nr);
-  SetupFileHash *score_hash = loadSetupFileHash(filename);
   int i, j;
 
-  server_scores.num_entries = 0;
-
-  if (score_hash == NULL)
-    return;
-
-  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+  for (i = 0; i < scores->num_entries; i++)
   {
-    score_entry = server_scores.entry[i];
-
-    for (j = 0; score_mapping[j].value != NULL; j++)
-    {
-      char token[10];
-
-      sprintf(token, "%02d.%d", i, j);
-
-      char *value = getHashEntry(score_hash, token);
-
-      if (value == NULL)
-       continue;
-
-      if (score_mapping[j].is_string)
-      {
-       char *score_value = (char *)score_mapping[j].value;
-       int value_size = score_mapping[j].string_size;
-
-       strncpy(score_value, value, value_size);
-       score_value[value_size] = '\0';
-      }
-      else
-      {
-       int *score_value = (int *)score_mapping[j].value;
-
-       *score_value = atoi(value);
-      }
-
-      server_scores.num_entries = i + 1;
-    }
+    int size = strlen(scores->entry[i].tape_basename);
 
-    server_scores.entry[i] = score_entry;
+    for (j = 0; j < MAX_SCORE_TAPE_BASENAME_LEN; j++)
+      putFile8Bit(file, (j < size ? scores->entry[i].tape_basename[j] : 0));
   }
-
-  freeSetupFileHash(score_hash);
 }
 
-void LoadServerScore(int nr, boolean download_score)
+static void SaveScoreToFilename(char *filename)
 {
-  if (!setup.use_api_server)
-    return;
-
-  // always start with reliable default values
-  setServerScoreInfoToDefaults();
-
-  // 1st step: load server scores from cache file (which may not exist)
-  // (this should prevent reading it while the thread is writing to it)
-  LoadServerScoreFromCache(nr);
+  FILE *file;
+  int info_chunk_size;
+  int name_chunk_size;
+  int scor_chunk_size;
+  int sc4r_chunk_size;
+  int time_chunk_size;
+  int tape_chunk_size;
+  boolean has_large_score_values;
+  int i;
 
-  if (download_score && runtime.use_api_server)
+  if (!(file = fopen(filename, MODE_WRITE)))
   {
-    // 2nd step: download server scores from score server to cache file
-    // (as thread, as it might time out if the server is not reachable)
-    ApiGetScoreAsThread(nr);
+    Warn("cannot save score file '%s'", filename);
+
+    return;
   }
-}
 
-static char *get_file_base64(char *filename)
-{
-  struct stat file_status;
+  info_chunk_size = 2 + (strlen(scores.level_identifier) + 1) + 2 + 2;
+  name_chunk_size = scores.num_entries * MAX_PLAYER_NAME_LEN;
+  scor_chunk_size = scores.num_entries * 2;
+  sc4r_chunk_size = scores.num_entries * 4;
+  time_chunk_size = scores.num_entries * 4;
+  tape_chunk_size = scores.num_entries * MAX_SCORE_TAPE_BASENAME_LEN;
 
-  if (stat(filename, &file_status) != 0)
-  {
-    Error("cannot stat file '%s'", filename);
+  has_large_score_values = FALSE;
+  for (i = 0; i < scores.num_entries; i++)
+    if (scores.entry[i].score > 0xffff)
+      has_large_score_values = TRUE;
 
-    return NULL;
-  }
+  putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
+  putFileChunkBE(file, "SCOR", CHUNK_SIZE_NONE);
 
-  int buffer_size = file_status.st_size;
-  byte *buffer = checked_malloc(buffer_size);
-  FILE *file;
-  int i;
+  putFileChunkBE(file, "VERS", SCORE_CHUNK_VERS_SIZE);
+  SaveScore_VERS(file, &scores);
 
-  if (!(file = fopen(filename, MODE_READ)))
-  {
-    Error("cannot open file '%s'", filename);
+  putFileChunkBE(file, "INFO", info_chunk_size);
+  SaveScore_INFO(file, &scores);
 
-    checked_free(buffer);
+  putFileChunkBE(file, "NAME", name_chunk_size);
+  SaveScore_NAME(file, &scores);
 
-    return NULL;
+  if (has_large_score_values)
+  {
+    putFileChunkBE(file, "SC4R", sc4r_chunk_size);
+    SaveScore_SC4R(file, &scores);
   }
-
-  for (i = 0; i < buffer_size; i++)
+  else
   {
-    int c = fgetc(file);
-
-    if (c == EOF)
-    {
-      Error("cannot read from input file '%s'", filename);
-
-      fclose(file);
-      checked_free(buffer);
-
-      return NULL;
-    }
-
-    buffer[i] = (byte)c;
+    putFileChunkBE(file, "SCOR", scor_chunk_size);
+    SaveScore_SCOR(file, &scores);
   }
 
-  fclose(file);
-
-  int buffer_encoded_size = base64_encoded_size(buffer_size);
-  char *buffer_encoded = checked_malloc(buffer_encoded_size);
+  putFileChunkBE(file, "TIME", time_chunk_size);
+  SaveScore_TIME(file, &scores);
 
-  base64_encode(buffer_encoded, buffer, buffer_size);
+  putFileChunkBE(file, "TAPE", tape_chunk_size);
+  SaveScore_TAPE(file, &scores);
 
-  checked_free(buffer);
+  fclose(file);
 
-  return buffer_encoded;
+  SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
-struct ApiAddScoreThreadData
+void SaveScore(int nr)
 {
-  int level_nr;
-  boolean tape_saved;
-  char *score_tape_filename;
-  struct ScoreEntry score_entry;
-};
+  char *filename = getScoreFilename(nr);
+  int i;
 
-static void *CreateThreadData_ApiAddScore(int nr, boolean tape_saved,
-                                         char *score_tape_filename)
-{
-  struct ApiAddScoreThreadData *data =
-    checked_malloc(sizeof(struct ApiAddScoreThreadData));
-  struct ScoreEntry *score_entry = &scores.entry[scores.last_added];
+  // used instead of "leveldir_current->subdir" (for network games)
+  InitScoreDirectory(levelset.identifier);
+
+  scores.file_version = FILE_VERSION_ACTUAL;
+  scores.game_version = GAME_VERSION_ACTUAL;
 
-  if (score_tape_filename == NULL)
-    score_tape_filename = getScoreTapeFilename(score_entry->tape_basename, nr);
+  strncpy(scores.level_identifier, levelset.identifier, MAX_FILENAME_LEN);
+  scores.level_identifier[MAX_FILENAME_LEN] = '\0';
+  scores.level_nr = level_nr;
 
-  data->level_nr = nr;
-  data->tape_saved = tape_saved;
-  data->score_entry = *score_entry;
-  data->score_tape_filename = getStringCopy(score_tape_filename);
+  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+    if (scores.entry[i].score == 0 &&
+        scores.entry[i].time == 0 &&
+        strEqual(scores.entry[i].name, EMPTY_PLAYER_NAME))
+      break;
 
-  return data;
-}
+  scores.num_entries = i;
 
-static void FreeThreadData_ApiAddScore(void *data_raw)
-{
-  struct ApiAddScoreThreadData *data = data_raw;
+  if (scores.num_entries == 0)
+    return;
 
-  checked_free(data->score_tape_filename);
-  checked_free(data);
+  SaveScoreToFilename(filename);
 }
 
-static boolean SetRequest_ApiAddScore(struct HttpRequest *request,
-                                     void *data_raw)
+static void LoadServerScoreFromCache(int nr)
 {
-  struct ApiAddScoreThreadData *data = data_raw;
-  struct ScoreEntry *score_entry = &data->score_entry;
-  char *score_tape_filename = data->score_tape_filename;
-  boolean tape_saved = data->tape_saved;
-  int level_nr = data->level_nr;
-
-  request->hostname = setup.api_server_hostname;
-  request->port     = API_SERVER_PORT;
-  request->method   = API_SERVER_METHOD;
-  request->uri      = API_SERVER_URI_ADD;
-
-  char *tape_base64 = get_file_base64(score_tape_filename);
-
-  if (tape_base64 == NULL)
+  struct ScoreEntry score_entry;
+  struct
   {
-    Error("loading and base64 encoding score tape file failed");
-
-    return FALSE;
+    void *value;
+    boolean is_string;
+    int string_size;
   }
+  score_mapping[] =
+  {
+    { &score_entry.score,              FALSE,  0                       },
+    { &score_entry.time,               FALSE,  0                       },
+    { score_entry.name,                        TRUE,   MAX_PLAYER_NAME_LEN     },
+    { score_entry.tape_basename,       TRUE,   MAX_FILENAME_LEN        },
+    { score_entry.tape_date,           TRUE,   MAX_ISO_DATE_LEN        },
+    { &score_entry.id,                 FALSE,  0                       },
+    { score_entry.platform,            TRUE,   MAX_PLATFORM_TEXT_LEN   },
+    { score_entry.version,             TRUE,   MAX_VERSION_TEXT_LEN    },
+    { score_entry.country_code,                TRUE,   MAX_COUNTRY_CODE_LEN    },
+    { score_entry.country_name,                TRUE,   MAX_COUNTRY_NAME_LEN    },
 
-  char *player_name_raw = score_entry->name;
-  char *player_uuid_raw = setup.player_uuid;
-
-  if (options.player_name != NULL && global.autoplay_leveldir != NULL)
-  {
-    player_name_raw = options.player_name;
-    player_uuid_raw = "";
-  }
-
-  char *levelset_identifier = getEscapedJSON(leveldir_current->identifier);
-  char *levelset_name       = getEscapedJSON(leveldir_current->name);
-  char *levelset_author     = getEscapedJSON(leveldir_current->author);
-  char *level_name          = getEscapedJSON(level.name);
-  char *level_author        = getEscapedJSON(level.author);
-  char *player_name         = getEscapedJSON(player_name_raw);
-  char *player_uuid         = getEscapedJSON(player_uuid_raw);
-
-  snprintf(request->body, MAX_HTTP_BODY_SIZE,
-          "{\n"
-          "%s"
-          "  \"game_version\":         \"%s\",\n"
-          "  \"game_platform\":        \"%s\",\n"
-          "  \"batch_time\":           \"%d\",\n"
-          "  \"levelset_identifier\":  \"%s\",\n"
-          "  \"levelset_name\":        \"%s\",\n"
-          "  \"levelset_author\":      \"%s\",\n"
-          "  \"levelset_num_levels\":  \"%d\",\n"
-          "  \"levelset_first_level\": \"%d\",\n"
-          "  \"level_nr\":             \"%d\",\n"
-          "  \"level_name\":           \"%s\",\n"
-          "  \"level_author\":         \"%s\",\n"
-          "  \"rate_time_over_score\": \"%d\",\n"
-          "  \"player_name\":          \"%s\",\n"
-          "  \"player_uuid\":          \"%s\",\n"
-          "  \"score\":                \"%d\",\n"
-          "  \"time\":                 \"%d\",\n"
-          "  \"tape_basename\":        \"%s\",\n"
-          "  \"tape_saved\":           \"%d\",\n"
-          "  \"tape\":                 \"%s\"\n"
-          "}\n",
-          getPasswordJSON(setup.api_server_password),
-          getProgramRealVersionString(),
-          getProgramPlatformString(),
-          (int)global.autoplay_time,
-          levelset_identifier,
-          levelset_name,
-          levelset_author,
-          leveldir_current->levels,
-          leveldir_current->first_level,
-          level_nr,
-          level_name,
-          level_author,
-          level.rate_time_over_score,
-          player_name,
-          player_uuid,
-          score_entry->score,
-          score_entry->time,
-          score_entry->tape_basename,
-          tape_saved,
-          tape_base64);
-
-  checked_free(tape_base64);
-
-  checked_free(levelset_identifier);
-  checked_free(levelset_name);
-  checked_free(levelset_author);
-  checked_free(level_name);
-  checked_free(level_author);
-  checked_free(player_name);
-  checked_free(player_uuid);
-
-  ConvertHttpRequestBodyToServerEncoding(request);
-
-  return TRUE;
-}
+    { NULL,                            FALSE,  0                       }
+  };
+  char *filename = getScoreCacheFilename(nr);
+  SetupFileHash *score_hash = loadSetupFileHash(filename);
+  int i, j;
 
-static void HandleResponse_ApiAddScore(struct HttpResponse *response,
-                                      void *data_raw)
-{
-  server_scores.uploaded = TRUE;
-}
+  server_scores.num_entries = 0;
 
-#if defined(PLATFORM_EMSCRIPTEN)
-static void Emscripten_ApiAddScore_Loaded(unsigned handle, void *data_raw,
-                                         void *buffer, unsigned int size)
-{
-  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+  if (score_hash == NULL)
+    return;
 
-  if (response != NULL)
+  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
   {
-    HandleResponse_ApiAddScore(response, data_raw);
+    score_entry = server_scores.entry[i];
 
-    checked_free(response);
-  }
-  else
-  {
-    Error("server response too large to handle (%d bytes)", size);
-  }
+    for (j = 0; score_mapping[j].value != NULL; j++)
+    {
+      char token[10];
 
-  FreeThreadData_ApiAddScore(data_raw);
-}
+      sprintf(token, "%02d.%d", i, j);
 
-static void Emscripten_ApiAddScore_Failed(unsigned handle, void *data_raw,
-                                         int code, const char *status)
-{
-  Error("server failed to handle request: %d %s", code, status);
+      char *value = getHashEntry(score_hash, token);
 
-  FreeThreadData_ApiAddScore(data_raw);
-}
+      if (value == NULL)
+       continue;
 
-static void Emscripten_ApiAddScore_Progress(unsigned handle, void *data_raw,
-                                           int bytes, int size)
-{
-  // nothing to do here
-}
+      if (score_mapping[j].is_string)
+      {
+       char *score_value = (char *)score_mapping[j].value;
+       int value_size = score_mapping[j].string_size;
 
-static void Emscripten_ApiAddScore_HttpRequest(struct HttpRequest *request,
-                                              void *data_raw)
-{
-  if (!SetRequest_ApiAddScore(request, data_raw))
-  {
-    FreeThreadData_ApiAddScore(data_raw);
+       strncpy(score_value, value, value_size);
+       score_value[value_size] = '\0';
+      }
+      else
+      {
+       int *score_value = (int *)score_mapping[j].value;
 
-    return;
+       *score_value = atoi(value);
+      }
+
+      server_scores.num_entries = i + 1;
+    }
+
+    server_scores.entry[i] = score_entry;
   }
 
-  emscripten_async_wget2_data(request->uri,
-                             request->method,
-                             request->body,
-                             data_raw,
-                             TRUE,
-                             Emscripten_ApiAddScore_Loaded,
-                             Emscripten_ApiAddScore_Failed,
-                             Emscripten_ApiAddScore_Progress);
+  freeSetupFileHash(score_hash);
 }
 
-#else
-
-static void ApiAddScore_HttpRequestExt(struct HttpRequest *request,
-                                      struct HttpResponse *response,
-                                      void *data_raw)
+void LoadServerScore(int nr, boolean download_score)
 {
-  if (!SetRequest_ApiAddScore(request, data_raw))
+  if (!setup.use_api_server)
     return;
 
-  if (!DoHttpRequest(request, response))
-  {
-    Error("HTTP request failed: %s", GetHttpError());
+  // always start with reliable default values
+  setServerScoreInfoToDefaults();
 
-    return;
-  }
+  // 1st step: load server scores from cache file (which may not exist)
+  // (this should prevent reading it while the thread is writing to it)
+  LoadServerScoreFromCache(nr);
 
-  if (!HTTP_SUCCESS(response->status_code))
+  if (download_score && runtime.use_api_server)
   {
-    Error("server failed to handle request: %d %s",
-         response->status_code,
-         response->status_text);
-
-    return;
+    // 2nd step: download server scores from score server to cache file
+    // (as thread, as it might time out if the server is not reachable)
+    ApiGetScoreAsThread(nr);
   }
-
-  HandleResponse_ApiAddScore(response, data_raw);
-}
-
-static void ApiAddScore_HttpRequest(struct HttpRequest *request,
-                                   struct HttpResponse *response,
-                                   void *data_raw)
-{
-  ApiAddScore_HttpRequestExt(request, response, data_raw);
-
-  FreeThreadData_ApiAddScore(data_raw);
 }
-#endif
 
-static int ApiAddScoreThread(void *data_raw)
+void PrepareScoreTapesForUpload(char *leveldir_subdir)
 {
-  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
-  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
-
-#if defined(PLATFORM_EMSCRIPTEN)
-  Emscripten_ApiAddScore_HttpRequest(request, data_raw);
-#else
-  ApiAddScore_HttpRequest(request, response, data_raw);
-#endif
-
-  checked_free(request);
-  checked_free(response);
+  MarkTapeDirectoryUploadsAsIncomplete(leveldir_subdir);
 
-  return 0;
-}
+  // if score tape not uploaded, ask for uploading missing tapes later
+  if (!setup.has_remaining_tapes)
+    setup.ask_for_remaining_tapes = TRUE;
 
-static void ApiAddScoreAsThread(int nr, boolean tape_saved,
-                               char *score_tape_filename)
-{
-  struct ApiAddScoreThreadData *data =
-    CreateThreadData_ApiAddScore(nr, tape_saved, score_tape_filename);
+  setup.provide_uploading_tapes = TRUE;
+  setup.has_remaining_tapes = TRUE;
 
-  ExecuteAsThread(ApiAddScoreThread,
-                 "ApiAddScore", data,
-                 "upload score to server");
+  SaveSetup_ServerSetup();
 }
 
 void SaveServerScore(int nr, boolean tape_saved)
 {
   if (!runtime.use_api_server)
+  {
+    PrepareScoreTapesForUpload(leveldir_current->subdir);
+
     return;
+  }
 
   ApiAddScoreAsThread(nr, tape_saved, NULL);
 }
@@ -9720,6 +10593,7 @@ void SaveServerScoreFromFile(int nr, boolean tape_saved,
 void LoadLocalAndServerScore(int nr, boolean download_score)
 {
   int last_added_local = scores.last_added_local;
+  boolean force_last_added = scores.force_last_added;
 
   // needed if only showing server scores
   setScoreInfoToDefaults();
@@ -9739,6 +10613,9 @@ void LoadLocalAndServerScore(int nr, boolean download_score)
     // merge local scores with scores from server
     MergeServerScore();
   }
+
+  if (force_last_added)
+    scores.force_last_added = force_last_added;
 }
 
 
@@ -9779,6 +10656,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_SWITCH,
     &setup.toons,                              "toons"
   },
+  {
+    TYPE_SWITCH,
+    &setup.global_animations,                  "global_animations"
+  },
   {
     TYPE_SWITCH,
     &setup.scroll_delay,                       "scroll_delay"
@@ -9807,6 +10688,14 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_SWITCH,
     &setup.autorecord,                         "automatic_tape_recording"
   },
+  {
+    TYPE_SWITCH,
+    &setup.autorecord_after_replay,            "autorecord_after_replay"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.auto_pause_on_start,                        "auto_pause_on_start"
+  },
   {
     TYPE_SWITCH,
     &setup.show_titlescreen,                   "show_titlescreen"
@@ -9827,6 +10716,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_SWITCH,
     &setup.skip_levels,                                "skip_levels"
   },
+  {
+    TYPE_SWITCH_3_STATES,
+    &setup.allow_skipping_levels,              "allow_skipping_levels"
+  },
   {
     TYPE_SWITCH,
     &setup.increment_levels,                   "increment_levels"
@@ -9915,6 +10808,62 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_INTEGER,
     &setup.game_frame_delay,                   "game_frame_delay"
   },
+  {
+    TYPE_INTEGER,
+    &setup.default_game_engine_type,           "default_game_engine_type"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.bd_skip_uncovering,                 "bd_skip_uncovering"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.bd_skip_hatching,                   "bd_skip_hatching"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.bd_scroll_delay,                    "bd_scroll_delay"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.bd_show_invisible_outbox,           "bd_show_invisible_outbox"
+  },
+  {
+    TYPE_SWITCH_3_STATES,
+    &setup.bd_smooth_movements,                        "bd_smooth_movements"
+  },
+  {
+    TYPE_SWITCH_3_STATES,
+    &setup.bd_pushing_graphics,                        "bd_pushing_graphics"
+  },
+  {
+    TYPE_SWITCH_3_STATES,
+    &setup.bd_up_down_graphics,                        "bd_up_down_graphics"
+  },
+  {
+    TYPE_SWITCH_3_STATES,
+    &setup.bd_skip_falling_sounds,             "bd_skip_falling_sounds"
+  },
+  {
+    TYPE_INTEGER,
+    &setup.bd_palette_c64,                     "bd_palette_c64"
+  },
+  {
+    TYPE_INTEGER,
+    &setup.bd_palette_c64dtv,                  "bd_palette_c64dtv"
+  },
+  {
+    TYPE_INTEGER,
+    &setup.bd_palette_atari,                   "bd_palette_atari"
+  },
+  {
+    TYPE_INTEGER,
+    &setup.bd_default_color_type,              "bd_default_color_type"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.bd_random_colors,                   "bd_random_colors"
+  },
   {
     TYPE_SWITCH,
     &setup.sp_show_border_elements,            "sp_show_border_elements"
@@ -9948,15 +10897,15 @@ static struct TokenInfo global_setup_tokens[] =
     &setup.music_set,                          "music_set"
   },
   {
-    TYPE_SWITCH3,
+    TYPE_SWITCH_3_STATES,
     &setup.override_level_graphics,            "override_level_graphics"
   },
   {
-    TYPE_SWITCH3,
+    TYPE_SWITCH_3_STATES,
     &setup.override_level_sounds,              "override_level_sounds"
   },
   {
-    TYPE_SWITCH3,
+    TYPE_SWITCH_3_STATES,
     &setup.override_level_music,               "override_level_music"
   },
   {
@@ -9971,6 +10920,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_INTEGER,
     &setup.volume_music,                       "volume_music"
   },
+  {
+    TYPE_SWITCH,
+    &setup.audio_sample_rate_44100,            "audio_sample_rate_44100"
+  },
   {
     TYPE_SWITCH,
     &setup.network_mode,                       "network_mode"
@@ -10023,6 +10976,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_INTEGER,
     &setup.touch.grid_ysize[1],                        "touch.virtual_buttons.1.ysize"
   },
+  {
+    TYPE_SWITCH,
+    &setup.touch.overlay_buttons,              "touch.overlay_buttons"
+  },
 };
 
 static struct TokenInfo auto_setup_tokens[] =
@@ -10039,6 +10996,10 @@ static struct TokenInfo server_setup_tokens[] =
     TYPE_STRING,
     &setup.player_uuid,                                "player_uuid"
   },
+  {
+    TYPE_INTEGER,
+    &setup.player_version,                     "player_version"
+  },
   {
     TYPE_SWITCH,
     &setup.use_api_server,          TEST_PREFIX        "use_api_server"
@@ -10055,10 +11016,22 @@ static struct TokenInfo server_setup_tokens[] =
     TYPE_SWITCH,
     &setup.ask_for_uploading_tapes, TEST_PREFIX        "ask_for_uploading_tapes"
   },
+  {
+    TYPE_SWITCH,
+    &setup.ask_for_remaining_tapes, TEST_PREFIX        "ask_for_remaining_tapes"
+  },
   {
     TYPE_SWITCH,
     &setup.provide_uploading_tapes, TEST_PREFIX        "provide_uploading_tapes"
   },
+  {
+    TYPE_SWITCH,
+    &setup.ask_for_using_api_server,TEST_PREFIX        "ask_for_using_api_server"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.has_remaining_tapes,     TEST_PREFIX        "has_remaining_tapes"
+  },
 };
 
 static struct TokenInfo editor_setup_tokens[] =
@@ -10099,6 +11072,14 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
     TYPE_SWITCH,
     &setup.editor_cascade.el_bd,               "editor.cascade.el_bd"
   },
+  {
+    TYPE_SWITCH,
+    &setup.editor_cascade.el_bdx,              "editor.cascade.el_bdx"
+  },
+  {
+    TYPE_SWITCH,
+    &setup.editor_cascade.el_bdx_effects,      "editor.cascade.el_bdx_effects"
+  },
   {
     TYPE_SWITCH,
     &setup.editor_cascade.el_em,               "editor.cascade.el_em"
@@ -10151,6 +11132,10 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
     TYPE_SWITCH,
     &setup.editor_cascade.el_ge,               "editor.cascade.el_ge"
   },
+  {
+    TYPE_SWITCH,
+    &setup.editor_cascade.el_es,               "editor.cascade.el_es"
+  },
   {
     TYPE_SWITCH,
     &setup.editor_cascade.el_ref,              "editor.cascade.el_ref"
@@ -10175,6 +11160,14 @@ static struct TokenInfo shortcut_setup_tokens[] =
     TYPE_KEY_X11,
     &setup.shortcut.load_game,                 "shortcut.load_game"
   },
+  {
+    TYPE_KEY_X11,
+    &setup.shortcut.restart_game,              "shortcut.restart_game"
+  },
+  {
+    TYPE_KEY_X11,
+    &setup.shortcut.pause_before_end,          "shortcut.pause_before_end"
+  },
   {
     TYPE_KEY_X11,
     &setup.shortcut.toggle_pause,              "shortcut.toggle_pause"
@@ -10251,6 +11244,14 @@ static struct TokenInfo shortcut_setup_tokens[] =
     TYPE_KEY_X11,
     &setup.shortcut.snap_down,                 "shortcut.snap_down"
   },
+  {
+    TYPE_KEY_X11,
+    &setup.shortcut.speed_fast,                        "shortcut.speed_fast"
+  },
+  {
+    TYPE_KEY_X11,
+    &setup.shortcut.speed_slow,                        "shortcut.speed_slow"
+  },
 };
 
 static struct SetupInputInfo setup_input;
@@ -10414,55 +11415,119 @@ static struct TokenInfo internal_setup_tokens[] =
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.choose_from_top_leveldir,  "choose_from_top_leveldir"
+    &setup.internal.choose_from_top_leveldir,  "choose_from_top_leveldir"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.show_scaling_in_title,     "show_scaling_in_title"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.create_user_levelset,      "create_user_levelset"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.info_screens_from_main,    "info_screens_from_main"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_game,                 "menu_game"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_engines,              "menu_engines"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_editor,               "menu_editor"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_graphics,             "menu_graphics"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_sound,                        "menu_sound"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_artwork,              "menu_artwork"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_input,                        "menu_input"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_touch,                        "menu_touch"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_shortcuts,            "menu_shortcuts"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_exit,                 "menu_exit"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_save_and_exit,                "menu_save_and_exit"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_shortcuts_various,    "menu_shortcuts_various"
+  },
+  {
+    TYPE_BOOLEAN,
+    &setup.internal.menu_shortcuts_focus,      "menu_shortcuts_focus"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.show_scaling_in_title,     "show_scaling_in_title"
+    &setup.internal.menu_shortcuts_tape,       "menu_shortcuts_tape"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.create_user_levelset,      "create_user_levelset"
+    &setup.internal.menu_shortcuts_sound,      "menu_shortcuts_sound"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_game,                 "menu_game"
+    &setup.internal.menu_shortcuts_snap,       "menu_shortcuts_snap"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_editor,               "menu_editor"
+    &setup.internal.menu_shortcuts_speed,      "menu_shortcuts_speed"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_graphics,             "menu_graphics"
+    &setup.internal.info_title,                        "info_title"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_sound,                        "menu_sound"
+    &setup.internal.info_elements,             "info_elements"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_artwork,              "menu_artwork"
+    &setup.internal.info_music,                        "info_music"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_input,                        "menu_input"
+    &setup.internal.info_credits,              "info_credits"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_touch,                        "menu_touch"
+    &setup.internal.info_program,              "info_program"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_shortcuts,            "menu_shortcuts"
+    &setup.internal.info_version,              "info_version"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_exit,                 "menu_exit"
+    &setup.internal.info_levelset,             "info_levelset"
   },
   {
     TYPE_BOOLEAN,
-    &setup.internal.menu_save_and_exit,                "menu_save_and_exit"
+    &setup.internal.info_exit,                 "info_exit"
   },
 };
 
@@ -10560,7 +11625,7 @@ static struct TokenInfo debug_setup_tokens[] =
     &setup.debug.show_frames_per_second,       "debug.show_frames_per_second"
   },
   {
-    TYPE_SWITCH3,
+    TYPE_SWITCH_3_STATES,
     &setup.debug.xsn_mode,                     "debug.xsn_mode"
   },
   {
@@ -10575,6 +11640,14 @@ static struct TokenInfo options_setup_tokens[] =
     TYPE_BOOLEAN,
     &setup.options.verbose,                    "options.verbose"
   },
+  {
+    TYPE_BOOLEAN,
+    &setup.options.debug,                      "options.debug"
+  },
+  {
+    TYPE_STRING,
+    &setup.options.debug_mode,                 "options.debug_mode"
+  },
 };
 
 static void setSetupInfoToDefaults(struct SetupInfo *si)
@@ -10590,6 +11663,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sound_music = TRUE;
   si->sound_simple = TRUE;
   si->toons = TRUE;
+  si->global_animations = TRUE;
   si->scroll_delay = TRUE;
   si->forced_scroll_delay = FALSE;
   si->scroll_delay_value = STD_SCROLL_DELAY;
@@ -10597,11 +11671,14 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->engine_snapshot_memory = SNAPSHOT_MEMORY_DEFAULT;
   si->fade_screens = TRUE;
   si->autorecord = TRUE;
+  si->autorecord_after_replay = TRUE;
+  si->auto_pause_on_start = FALSE;
   si->show_titlescreen = TRUE;
   si->quick_doors = FALSE;
   si->team_mode = FALSE;
   si->handicap = TRUE;
   si->skip_levels = TRUE;
+  si->allow_skipping_levels = STATE_ASK;
   si->increment_levels = TRUE;
   si->auto_play_next_level = TRUE;
   si->count_score_after_game = TRUE;
@@ -10624,6 +11701,20 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->prefer_extra_panel_items = TRUE;
   si->game_speed_extended = FALSE;
   si->game_frame_delay = GAME_FRAME_DELAY;
+  si->default_game_engine_type = GAME_ENGINE_TYPE_RND;
+  si->bd_skip_uncovering = FALSE;
+  si->bd_skip_hatching = FALSE;
+  si->bd_scroll_delay = TRUE;
+  si->bd_show_invisible_outbox = FALSE;
+  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_palette_c64 = GD_DEFAULT_PALETTE_C64;
+  si->bd_palette_c64dtv = GD_DEFAULT_PALETTE_C64DTV;
+  si->bd_palette_atari = GD_DEFAULT_PALETTE_ATARI;
+  si->bd_default_color_type = GD_DEFAULT_COLOR_TYPE;
+  si->bd_random_colors = FALSE;
   si->sp_show_border_elements = FALSE;
   si->small_game_graphics = FALSE;
   si->show_load_save_buttons = FALSE;
@@ -10634,13 +11725,14 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sounds_set   = getStringCopy(SND_CLASSIC_SUBDIR);
   si->music_set    = getStringCopy(MUS_CLASSIC_SUBDIR);
 
-  si->override_level_graphics = FALSE;
-  si->override_level_sounds = FALSE;
-  si->override_level_music = FALSE;
+  si->override_level_graphics = STATE_FALSE;
+  si->override_level_sounds = STATE_FALSE;
+  si->override_level_music = STATE_FALSE;
 
   si->volume_simple = 100;             // percent
   si->volume_loops = 100;              // percent
   si->volume_music = 100;              // percent
+  si->audio_sample_rate_44100 = FALSE;
 
   si->network_mode = FALSE;
   si->network_player_nr = 0;           // first player
@@ -10702,7 +11794,11 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->touch.grid_initialized           = video.initialized;
 
+  si->touch.overlay_buttons            = FALSE;
+
   si->editor.el_boulderdash            = TRUE;
+  si->editor.el_boulderdash_native     = TRUE;
+  si->editor.el_boulderdash_effects    = TRUE;
   si->editor.el_emerald_mine           = TRUE;
   si->editor.el_emerald_mine_club      = TRUE;
   si->editor.el_more                   = TRUE;
@@ -10733,6 +11829,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->shortcut.save_game       = DEFAULT_KEY_SAVE_GAME;
   si->shortcut.load_game       = DEFAULT_KEY_LOAD_GAME;
+  si->shortcut.restart_game    = DEFAULT_KEY_RESTART_GAME;
+  si->shortcut.pause_before_end        = DEFAULT_KEY_PAUSE_BEFORE_END;
   si->shortcut.toggle_pause    = DEFAULT_KEY_TOGGLE_PAUSE;
 
   si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
@@ -10757,10 +11855,13 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->shortcut.snap_up         = DEFAULT_KEY_SNAP_UP;
   si->shortcut.snap_down       = DEFAULT_KEY_SNAP_DOWN;
 
+  si->shortcut.speed_fast      = DEFAULT_KEY_SPEED_FAST;
+  si->shortcut.speed_slow      = DEFAULT_KEY_SPEED_SLOW;
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     si->input[i].use_joystick = FALSE;
-    si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
+    si->input[i].joy.device_name = getStringCopy(getDeviceNameFromJoystickNr(i));
     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
@@ -10804,6 +11905,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->internal.choose_from_top_leveldir = FALSE;
   si->internal.show_scaling_in_title = TRUE;
   si->internal.create_user_levelset = TRUE;
+  si->internal.info_screens_from_main = FALSE;
 
   si->internal.default_window_width  = WIN_XSIZE_DEFAULT;
   si->internal.default_window_height = WIN_YSIZE_DEFAULT;
@@ -10835,13 +11937,16 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->debug.show_frames_per_second = FALSE;
 
-  si->debug.xsn_mode = AUTO;
+  si->debug.xsn_mode = STATE_AUTO;
   si->debug.xsn_percent = 0;
 
   si->options.verbose = FALSE;
+  si->options.debug = FALSE;
+  si->options.debug_mode = getStringCopy(ARG_UNDEFINED_STRING);
 
 #if defined(PLATFORM_ANDROID)
   si->fullscreen = TRUE;
+  si->touch.overlay_buttons = TRUE;
 #endif
 
   setHideSetupEntry(&setup.debug.xsn_mode);
@@ -10855,17 +11960,23 @@ static void setSetupInfoToDefaults_AutoSetup(struct SetupInfo *si)
 static void setSetupInfoToDefaults_ServerSetup(struct SetupInfo *si)
 {
   si->player_uuid = NULL;      // (will be set later)
+  si->player_version = 1;      // (will be set later)
 
   si->use_api_server = TRUE;
   si->api_server_hostname = getStringCopy(API_SERVER_HOSTNAME);
   si->api_server_password = getStringCopy(UNDEFINED_PASSWORD);
   si->ask_for_uploading_tapes = TRUE;
+  si->ask_for_remaining_tapes = FALSE;
   si->provide_uploading_tapes = TRUE;
+  si->ask_for_using_api_server = TRUE;
+  si->has_remaining_tapes = FALSE;
 }
 
 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
 {
   si->editor_cascade.el_bd             = TRUE;
+  si->editor_cascade.el_bdx            = TRUE;
+  si->editor_cascade.el_bdx_effects    = FALSE;
   si->editor_cascade.el_em             = TRUE;
   si->editor_cascade.el_emc            = TRUE;
   si->editor_cascade.el_rnd            = TRUE;
@@ -10881,6 +11992,7 @@ static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
   si->editor_cascade.el_steel_chars    = FALSE;
   si->editor_cascade.el_ce             = FALSE;
   si->editor_cascade.el_ge             = FALSE;
+  si->editor_cascade.el_es             = FALSE;
   si->editor_cascade.el_ref            = FALSE;
   si->editor_cascade.el_user           = FALSE;
   si->editor_cascade.el_dynamic                = FALSE;
@@ -11160,6 +12272,12 @@ void LoadSetup_Default(void)
   // try to load setup values from default setup file
   filename = getDefaultSetupFilename();
 
+  if (fileExists(filename))
+    LoadSetupFromFilename(filename);
+
+  // try to load setup values from platform setup file
+  filename = getPlatformSetupFilename();
+
   if (fileExists(filename))
     LoadSetupFromFilename(filename);
 
@@ -11214,6 +12332,7 @@ void LoadSetup_ServerSetup(void)
   {
     // player UUID does not yet exist in setup file
     setup.player_uuid = getStringCopy(getUUID());
+    setup.player_version = 2;
 
     SaveSetup_ServerSetup();
   }
@@ -11386,7 +12505,7 @@ void SaveSetup_Default(void)
   fprintf(file, "\n");
   for (i = 0; i < ARRAY_SIZE(debug_setup_tokens); i++)
     if (!strPrefix(debug_setup_tokens[i].text, "debug.xsn_") ||
-       setup.debug.xsn_mode != AUTO)
+       setup.debug.xsn_mode != STATE_AUTO)
       fprintf(file, "%s\n", getSetupLine(debug_setup_tokens, "", i));
 
   fprintf(file, "\n");
@@ -11686,8 +12805,9 @@ static boolean string_has_parameter(char *s, char *s_contained)
     char next_char = s[strlen(s_contained)];
 
     // check if next character is delimiter or whitespace
-    return (next_char == ',' || next_char == '\0' ||
-           next_char == ' ' || next_char == '\t' ? TRUE : FALSE);
+    if (next_char == ',' || next_char == '\0' ||
+       next_char == ' ' || next_char == '\t')
+      return TRUE;
   }
 
   // check if string contains another parameter string after a comma
@@ -11705,6 +12825,85 @@ static boolean string_has_parameter(char *s, char *s_contained)
   return string_has_parameter(substring, s_contained);
 }
 
+static int get_anim_parameter_value_ce(char *s)
+{
+  char *s_ptr = s;
+  char *pattern_1 = "ce_change:custom_";
+  char *pattern_2 = ".page_";
+  int pattern_1_len = strlen(pattern_1);
+  char *matching_char = strstr(s_ptr, pattern_1);
+  int result = ANIM_EVENT_NONE;
+
+  if (matching_char == NULL)
+    return ANIM_EVENT_NONE;
+
+  result = ANIM_EVENT_CE_CHANGE;
+
+  s_ptr = matching_char + pattern_1_len;
+
+  // check for custom element number ("custom_X", "custom_XX" or "custom_XXX")
+  if (*s_ptr >= '0' && *s_ptr <= '9')
+  {
+    int gic_ce_nr = (*s_ptr++ - '0');
+
+    if (*s_ptr >= '0' && *s_ptr <= '9')
+    {
+      gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+
+      if (*s_ptr >= '0' && *s_ptr <= '9')
+       gic_ce_nr = 10 * gic_ce_nr + (*s_ptr++ - '0');
+    }
+
+    if (gic_ce_nr < 1 || gic_ce_nr > NUM_CUSTOM_ELEMENTS)
+      return ANIM_EVENT_NONE;
+
+    // custom element stored as 0 to 255
+    gic_ce_nr--;
+
+    result |= gic_ce_nr << ANIM_EVENT_CE_BIT;
+  }
+  else
+  {
+    // invalid custom element number specified
+
+    return ANIM_EVENT_NONE;
+  }
+
+  // check for change page number ("page_X" or "page_XX") (optional)
+  if (strPrefix(s_ptr, pattern_2))
+  {
+    s_ptr += strlen(pattern_2);
+
+    if (*s_ptr >= '0' && *s_ptr <= '9')
+    {
+      int gic_page_nr = (*s_ptr++ - '0');
+
+      if (*s_ptr >= '0' && *s_ptr <= '9')
+       gic_page_nr = 10 * gic_page_nr + (*s_ptr++ - '0');
+
+      if (gic_page_nr < 1 || gic_page_nr > MAX_CHANGE_PAGES)
+       return ANIM_EVENT_NONE;
+
+      // change page stored as 1 to 32 (0 means "all change pages")
+
+      result |= gic_page_nr << ANIM_EVENT_PAGE_BIT;
+    }
+    else
+    {
+      // invalid animation part number specified
+
+      return ANIM_EVENT_NONE;
+    }
+  }
+
+  // discard result if next character is neither delimiter nor whitespace
+  if (!(*s_ptr == ',' || *s_ptr == '\0' ||
+       *s_ptr == ' ' || *s_ptr == '\t'))
+    return ANIM_EVENT_NONE;
+
+  return result;
+}
+
 static int get_anim_parameter_value(char *s)
 {
   int event_value[] =
@@ -11730,6 +12929,11 @@ static int get_anim_parameter_value(char *s)
   int result = ANIM_EVENT_NONE;
   int i;
 
+  result = get_anim_parameter_value_ce(s);
+
+  if (result != ANIM_EVENT_NONE)
+    return result;
+
   for (i = 0; i < ARRAY_SIZE(event_value); i++)
   {
     matching_char = strstr(s_ptr, pattern_1[i]);
@@ -11859,6 +13063,18 @@ static int get_anim_action_parameter_value(char *token)
       result = -(int)key;
   }
 
+  if (result == -1)
+  {
+    if (isURL(token))
+    {
+      result = get_hash_from_string(token);    // unsigned int => int
+      result = ABS(result);                    // may be negative now
+      result += (result < MAX_IMAGE_FILES ? MAX_IMAGE_FILES : 0);
+
+      setHashEntry(anim_url_hash, int2str(result, 0), token);
+    }
+  }
+
   if (result == -1)
     result = ANIM_EVENT_ACTION_NONE;
 
@@ -11887,6 +13103,8 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              strEqual(value, "lower")  ? POS_LOWER :
              strEqual(value, "bottom") ? POS_BOTTOM :
              strEqual(value, "any")    ? POS_ANY :
+             strEqual(value, "ce")     ? POS_CE :
+             strEqual(value, "ce_trigger") ? POS_CE_TRIGGER :
              strEqual(value, "last")   ? POS_LAST : POS_UNDEFINED);
   }
   else if (strEqual(suffix, ".align"))
@@ -11911,6 +13129,7 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              string_has_parameter(value, "pingpong")   ? ANIM_PINGPONG :
              string_has_parameter(value, "pingpong2")  ? ANIM_PINGPONG2 :
              string_has_parameter(value, "random")     ? ANIM_RANDOM :
+             string_has_parameter(value, "random_static") ? ANIM_RANDOM_STATIC :
              string_has_parameter(value, "ce_value")   ? ANIM_CE_VALUE :
              string_has_parameter(value, "ce_score")   ? ANIM_CE_SCORE :
              string_has_parameter(value, "ce_delay")   ? ANIM_CE_DELAY :
@@ -11918,6 +13137,8 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
              string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
              string_has_parameter(value, "centered")   ? ANIM_CENTERED :
              string_has_parameter(value, "all")        ? ANIM_ALL :
+             string_has_parameter(value, "tiled")      ? ANIM_TILED :
+             string_has_parameter(value, "level_nr")   ? ANIM_LEVEL_NR :
              ANIM_DEFAULT);
 
     if (string_has_parameter(value, "once"))
@@ -11948,7 +13169,7 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
   else if (strEqual(suffix, ".class"))
   {
     result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
-             get_hash_from_key(value));
+             get_hash_from_string(value));
   }
   else if (strEqual(suffix, ".style"))
   {
@@ -11974,11 +13195,16 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
 
     if (string_has_parameter(value, "multiple_actions"))
       result |= STYLE_MULTIPLE_ACTIONS;
+
+    if (string_has_parameter(value, "consume_ce_event"))
+      result |= STYLE_CONSUME_CE_EVENT;
   }
   else if (strEqual(suffix, ".fade_mode"))
   {
     result = (string_has_parameter(value, "none")      ? FADE_MODE_NONE :
              string_has_parameter(value, "fade")       ? FADE_MODE_FADE :
+             string_has_parameter(value, "fade_in")    ? FADE_MODE_FADE_IN :
+             string_has_parameter(value, "fade_out")   ? FADE_MODE_FADE_OUT :
              string_has_parameter(value, "crossfade")  ? FADE_MODE_CROSSFADE :
              string_has_parameter(value, "melt")       ? FADE_MODE_MELT :
              string_has_parameter(value, "curtain")    ? FADE_MODE_CURTAIN :
@@ -12025,14 +13251,18 @@ static int get_token_parameter_value(char *token, char *value_raw)
   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
 }
 
-void InitMenuDesignSettings_Static(void)
+void InitMenuDesignSettings_FromHash(SetupFileHash *setup_file_hash,
+                                    boolean ignore_defaults)
 {
   int i;
 
-  // always start with reliable default values from static default config
   for (i = 0; image_config_vars[i].token != NULL; i++)
   {
-    char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
+    char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
+
+    // (ignore definitions set to "[DEFAULT]" which are already initialized)
+    if (ignore_defaults && strEqual(value, ARG_DEFAULT))
+      continue;
 
     if (value != NULL)
       *image_config_vars[i].value =
@@ -12040,6 +13270,12 @@ void InitMenuDesignSettings_Static(void)
   }
 }
 
+void InitMenuDesignSettings_Static(void)
+{
+  // always start with reliable default values from static default config
+  InitMenuDesignSettings_FromHash(image_config_hash, FALSE);
+}
+
 static void InitMenuDesignSettings_SpecialPreProcessing(void)
 {
   int i;
@@ -12245,7 +13481,7 @@ static void InitMenuDesignSettings_SpecialPostProcessing(void)
       vp_playfield->width = MIN(vp_playfield->width, vp_playfield->max_width);
 
     if (vp_playfield->max_height != -1)
-      vp_playfield->height = MIN(vp_playfield->height,vp_playfield->max_height);
+      vp_playfield->height = MIN(vp_playfield->height, vp_playfield->max_height);
 
     // adjust playfield position according to specified alignment
 
@@ -12480,6 +13716,45 @@ static void InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics(void)
   }
 }
 
+static void InitMenuDesignSettings_PreviewPlayers_Ext(SetupFileHash *hash,
+                                                      boolean initialize)
+{
+  // special case: check if network and preview player positions are redefined,
+  // to compare this later against the main menu level preview being redefined
+  struct TokenIntPtrInfo menu_config_players[] =
+  {
+    { "main.network_players.x",        &menu.main.network_players.redefined    },
+    { "main.network_players.y",        &menu.main.network_players.redefined    },
+    { "main.preview_players.x",        &menu.main.preview_players.redefined    },
+    { "main.preview_players.y",        &menu.main.preview_players.redefined    },
+    { "preview.x",             &preview.redefined                      },
+    { "preview.y",             &preview.redefined                      }
+  };
+  int i;
+
+  if (initialize)
+  {
+    for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+      *menu_config_players[i].value = FALSE;
+  }
+  else
+  {
+    for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
+      if (getHashEntry(hash, menu_config_players[i].token) != NULL)
+        *menu_config_players[i].value = TRUE;
+  }
+}
+
+static void InitMenuDesignSettings_PreviewPlayers(void)
+{
+  InitMenuDesignSettings_PreviewPlayers_Ext(NULL, TRUE);
+}
+
+static void InitMenuDesignSettings_PreviewPlayers_FromHash(SetupFileHash *hash)
+{
+  InitMenuDesignSettings_PreviewPlayers_Ext(hash, FALSE);
+}
+
 static void LoadMenuDesignSettingsFromFilename(char *filename)
 {
   static struct TitleFadingInfo tfi;
@@ -12614,7 +13889,9 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
     {
       { "menu.draw_xoffset.INFO",      &menu.draw_xoffset_info[i]      },
       { "menu.draw_yoffset.INFO",      &menu.draw_yoffset_info[i]      },
-      { "menu.list_size.INFO",         &menu.list_size_info[i]         }
+      { "menu.list_size.INFO",         &menu.list_size_info[i]         },
+      { "menu.list_entry_size.INFO",   &menu.list_entry_size_info[i]   },
+      { "menu.tile_size.INFO",         &menu.tile_size_info[i]         }
     };
 
     for (j = 0; j < ARRAY_SIZE(menu_config); j++)
@@ -12654,6 +13931,7 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
     struct TokenIntPtrInfo menu_config[] =
     {
       { "menu.left_spacing.INFO",      &menu.left_spacing_info[i]      },
+      { "menu.middle_spacing.INFO",    &menu.middle_spacing_info[i]    },
       { "menu.right_spacing.INFO",     &menu.right_spacing_info[i]     },
       { "menu.top_spacing.INFO",       &menu.top_spacing_info[i]       },
       { "menu.bottom_spacing.INFO",    &menu.bottom_spacing_info[i]    },
@@ -12818,35 +14096,11 @@ static void LoadMenuDesignSettingsFromFilename(char *filename)
     }
   }
 
-  // special case: check if network and preview player positions are redefined,
-  // to compare this later against the main menu level preview being redefined
-  struct TokenIntPtrInfo menu_config_players[] =
-  {
-    { "main.network_players.x",        &menu.main.network_players.redefined    },
-    { "main.network_players.y",        &menu.main.network_players.redefined    },
-    { "main.preview_players.x",        &menu.main.preview_players.redefined    },
-    { "main.preview_players.y",        &menu.main.preview_players.redefined    },
-    { "preview.x",             &preview.redefined                      },
-    { "preview.y",             &preview.redefined                      }
-  };
-
-  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
-    *menu_config_players[i].value = FALSE;
-
-  for (i = 0; i < ARRAY_SIZE(menu_config_players); i++)
-    if (getHashEntry(setup_file_hash, menu_config_players[i].token) != NULL)
-      *menu_config_players[i].value = TRUE;
-
   // read (and overwrite with) values that may be specified in config file
-  for (i = 0; image_config_vars[i].token != NULL; i++)
-  {
-    char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
+  InitMenuDesignSettings_FromHash(setup_file_hash, TRUE);
 
-    // (ignore definitions set to "[DEFAULT]" which are already initialized)
-    if (value != NULL && !strEqual(value, ARG_DEFAULT))
-      *image_config_vars[i].value =
-       get_token_parameter_value(image_config_vars[i].token, value);
-  }
+  // special case: check if network and preview player positions are redefined
+  InitMenuDesignSettings_PreviewPlayers_FromHash(setup_file_hash);
 
   freeSetupFileHash(setup_file_hash);
 }
@@ -12857,6 +14111,7 @@ void LoadMenuDesignSettings(void)
 
   InitMenuDesignSettings_Static();
   InitMenuDesignSettings_SpecialPreProcessing();
+  InitMenuDesignSettings_PreviewPlayers();
 
   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
   {
@@ -12880,6 +14135,65 @@ void LoadMenuDesignSettings_AfterGraphics(void)
   InitMenuDesignSettings_SpecialPostProcessing_AfterGraphics();
 }
 
+void InitSoundSettings_FromHash(SetupFileHash *setup_file_hash,
+                               boolean ignore_defaults)
+{
+  int i;
+
+  for (i = 0; sound_config_vars[i].token != NULL; i++)
+  {
+    char *value = getHashEntry(setup_file_hash, sound_config_vars[i].token);
+
+    // (ignore definitions set to "[DEFAULT]" which are already initialized)
+    if (ignore_defaults && strEqual(value, ARG_DEFAULT))
+      continue;
+
+    if (value != NULL)
+      *sound_config_vars[i].value =
+       get_token_parameter_value(sound_config_vars[i].token, value);
+  }
+}
+
+void InitSoundSettings_Static(void)
+{
+  // always start with reliable default values from static default config
+  InitSoundSettings_FromHash(sound_config_hash, FALSE);
+}
+
+static void LoadSoundSettingsFromFilename(char *filename)
+{
+  SetupFileHash *setup_file_hash;
+
+  if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+    return;
+
+  // read (and overwrite with) values that may be specified in config file
+  InitSoundSettings_FromHash(setup_file_hash, TRUE);
+
+  freeSetupFileHash(setup_file_hash);
+}
+
+void LoadSoundSettings(void)
+{
+  char *filename_base = UNDEFINED_FILENAME, *filename_local;
+
+  InitSoundSettings_Static();
+
+  if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_SOUNDS))
+  {
+    // first look for special settings configured in level series config
+    filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_SOUNDS);
+
+    if (fileExists(filename_base))
+      LoadSoundSettingsFromFilename(filename_base);
+  }
+
+  filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_SOUNDS);
+
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
+    LoadSoundSettingsFromFilename(filename_local);
+}
+
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
 {
   char *filename = getEditorSetupFilename();
@@ -12979,11 +14293,13 @@ static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
     { "artist_header", &tmp_music_file_info.artist_header      },
     { "album_header",  &tmp_music_file_info.album_header       },
     { "year_header",   &tmp_music_file_info.year_header        },
+    { "played_header", &tmp_music_file_info.played_header      },
 
     { "title",         &tmp_music_file_info.title              },
     { "artist",                &tmp_music_file_info.artist             },
     { "album",         &tmp_music_file_info.album              },
     { "year",          &tmp_music_file_info.year               },
+    { "played",                &tmp_music_file_info.played             },
 
     { NULL,            NULL                                    },
   };
@@ -13079,14 +14395,12 @@ static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
 
 void LoadMusicInfo(void)
 {
-  char *music_directory = getCustomMusicDirectory();
+  int num_music_noconf = getMusicListSize_NoConf();
   int num_music = getMusicListSize();
-  int num_music_noconf = 0;
   int num_sounds = getSoundListSize();
-  Directory *dir;
-  DirectoryEntry *dir_entry;
   struct FileInfo *music, *sound;
   struct MusicFileInfo *next, **new;
+
   int i;
 
   while (music_file_info != NULL)
@@ -13099,11 +14413,13 @@ void LoadMusicInfo(void)
     checked_free(music_file_info->artist_header);
     checked_free(music_file_info->album_header);
     checked_free(music_file_info->year_header);
+    checked_free(music_file_info->played_header);
 
     checked_free(music_file_info->title);
     checked_free(music_file_info->artist);
     checked_free(music_file_info->album);
     checked_free(music_file_info->year);
+    checked_free(music_file_info->played);
 
     free(music_file_info);
 
@@ -13112,76 +14428,68 @@ void LoadMusicInfo(void)
 
   new = &music_file_info;
 
-  for (i = 0; i < num_music; i++)
+  // get (configured or unconfigured) music file info for all levels
+  for (i = leveldir_current->first_level;
+       i <= leveldir_current->last_level; i++)
   {
-    music = getMusicListEntry(i);
+    int music_nr;
 
-    if (music->filename == NULL)
-      continue;
+    if (levelset.music[i] != MUS_UNDEFINED)
+    {
+      // get music file info for configured level music
+      music_nr = levelset.music[i];
+    }
+    else if (num_music_noconf > 0)
+    {
+      // get music file info for unconfigured level music
+      int level_pos = i - leveldir_current->first_level;
 
-    if (strEqual(music->filename, UNDEFINED_FILENAME))
+      music_nr = MAP_NOCONF_MUSIC(level_pos % num_music_noconf);
+    }
+    else
+    {
       continue;
+    }
 
-    // a configured file may be not recognized as music
-    if (!FileIsMusic(music->filename))
+    char *basename = getMusicInfoEntryFilename(music_nr);
+
+    if (basename == NULL)
       continue;
 
-    if (!music_info_listed(music_file_info, music->filename))
+    if (!music_info_listed(music_file_info, basename))
     {
-      *new = get_music_file_info(music->filename, i);
+      *new = get_music_file_info(basename, music_nr);
 
       if (*new != NULL)
        new = &(*new)->next;
     }
   }
 
-  if ((dir = openDirectory(music_directory)) == NULL)
-  {
-    Warn("cannot read music directory '%s'", music_directory);
-
-    return;
-  }
-
-  while ((dir_entry = readDirectory(dir)) != NULL)     // loop all entries
+  // get music file info for all remaining configured music files
+  for (i = 0; i < num_music; i++)
   {
-    char *basename = dir_entry->basename;
-    boolean music_already_used = FALSE;
-    int i;
-
-    // skip all music files that are configured in music config file
-    for (i = 0; i < num_music; i++)
-    {
-      music = getMusicListEntry(i);
-
-      if (music->filename == NULL)
-       continue;
+    music = getMusicListEntry(i);
 
-      if (strEqual(basename, music->filename))
-      {
-       music_already_used = TRUE;
-       break;
-      }
-    }
+    if (music->filename == NULL)
+      continue;
 
-    if (music_already_used)
+    if (strEqual(music->filename, UNDEFINED_FILENAME))
       continue;
 
-    if (!FileIsMusic(dir_entry->filename))
+    // a configured file may be not recognized as music
+    if (!FileIsMusic(music->filename))
       continue;
 
-    if (!music_info_listed(music_file_info, basename))
+    if (!music_info_listed(music_file_info, music->filename))
     {
-      *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
+      *new = get_music_file_info(music->filename, i);
 
       if (*new != NULL)
        new = &(*new)->next;
     }
-
-    num_music_noconf++;
   }
 
-  closeDirectory(dir);
-
+  // get sound file info for all configured sound files
   for (i = 0; i < num_sounds; i++)
   {
     sound = getSoundListEntry(i);
@@ -13203,6 +14511,18 @@ void LoadMusicInfo(void)
        new = &(*new)->next;
     }
   }
+
+  // add pointers to previous list nodes
+
+  struct MusicFileInfo *node = music_file_info;
+
+  while (node != NULL)
+  {
+    if (node->next)
+      node->next->prev = node;
+
+    node = node->next;
+  }
 }
 
 static void add_helpanim_entry(int element, int action, int direction,
@@ -13705,8 +15025,25 @@ void CreateCollectElementImages(void)
   int dst_width  = anim_width * 2;
   int dst_height = anim_height * num_collect_images / 2;
   Bitmap *dst_bitmap = CreateBitmap(dst_width, dst_height, DEFAULT_DEPTH);
-  char *basename = "RocksCollect.bmp";
-  char *filename = getPath2(global.create_collect_images_dir, basename);
+  char *basename_bmp = "RocksCollect.bmp";
+  char *basename_png = "RocksCollect.png";
+  char *filename_bmp = getPath2(global.create_collect_images_dir, basename_bmp);
+  char *filename_png = getPath2(global.create_collect_images_dir, basename_png);
+  int len_filename_bmp = strlen(filename_bmp);
+  int len_filename_png = strlen(filename_png);
+  int max_command_len = MAX_FILENAME_LEN + len_filename_bmp + len_filename_png;
+  char cmd_convert[max_command_len];
+
+  snprintf(cmd_convert, max_command_len, "convert \"%s\" \"%s\"",
+          filename_bmp,
+          filename_png);
+
+  // force using RGBA surface for destination bitmap
+  SDL_SetColorKey(dst_bitmap->surface, SET_TRANSPARENT_PIXEL,
+                 SDL_MapRGB(dst_bitmap->surface->format, 0x00, 0x00, 0x00));
+
+  dst_bitmap->surface =
+    SDL_ConvertSurfaceFormat(dst_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0);
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -13728,6 +15065,13 @@ void CreateCollectElementImages(void)
     BlitBitmap(src_bitmap, tmp_bitmap, src_x, src_y,
               tile_size, tile_size, 0, 0);
 
+    // force using RGBA surface for temporary bitmap (using transparent black)
+    SDL_SetColorKey(tmp_bitmap->surface, SET_TRANSPARENT_PIXEL,
+                   SDL_MapRGB(tmp_bitmap->surface->format, 0x00, 0x00, 0x00));
+
+    tmp_bitmap->surface =
+      SDL_ConvertSurfaceFormat(tmp_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0);
+
     tmp_bitmap->surface_masked = tmp_bitmap->surface;
 
     for (j = 0; j < anim_frames; j++)
@@ -13748,9 +15092,9 @@ void CreateCollectElementImages(void)
        frame_bitmap = half_bitmap;
       }
 
-      BlitBitmap(frame_bitmap, dst_bitmap, 0, 0,
-                frame_size_final, frame_size_final,
-                dst_x + j * tile_size + offset, dst_y + offset);
+      BlitBitmapMasked(frame_bitmap, dst_bitmap, 0, 0,
+                      frame_size_final, frame_size_final,
+                      dst_x + j * tile_size + offset, dst_y + offset);
 
       FreeBitmap(frame_bitmap);
     }
@@ -13762,11 +15106,18 @@ void CreateCollectElementImages(void)
     pos_collect_images++;
   }
 
-  if (SDL_SaveBMP(dst_bitmap->surface, filename) != 0)
-    Fail("cannot save element collecting image file '%s'", filename);
+  if (SDL_SaveBMP(dst_bitmap->surface, filename_bmp) != 0)
+    Fail("cannot save element collecting image file '%s'", filename_bmp);
 
   FreeBitmap(dst_bitmap);
 
+  Info("Converting image file from BMP to PNG ...");
+
+  if (system(cmd_convert) != 0)
+    Fail("converting image file failed");
+
+  unlink(filename_bmp);
+
   Info("Done.");
 
   CloseAllAndExit(0);
index e32fcd80c2c82c773d35117b35e090d36057443c..c122716b60fb8dc672db78903bad35f43f8961a0 100644 (file)
@@ -29,15 +29,13 @@ void setElementChangePages(struct ElementInfo *, int);
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *);
 void copyElementInfo(struct ElementInfo *, struct ElementInfo *);
 
+boolean isLevelsetFilename_BD(char *);
 char *getDefaultLevelFilename(int);
 char *getLocalLevelTemplateFilename(void);
 char *getGlobalLevelTemplateFilename(void);
 
 int getMappedElement(int);
 
-void ExecuteAsThread(SDL_ThreadFunction, char *, void *, char *);
-char *getPasswordJSON(char *);
-
 void LoadLevelFromFilename(struct LevelInfo *, char *);
 void LoadLevel(int);
 void LoadLevelTemplate(int);
@@ -48,6 +46,8 @@ void SaveLevelTemplate(void);
 void SaveNativeLevel(struct LevelInfo *);
 void DumpLevel(struct LevelInfo *);
 void DumpLevels(void);
+void DumpLevelsetFromFilename_BD(char *);
+void DumpLevelset(void);
 boolean SaveLevelChecked(int);
 
 void CopyNativeLevel_RND_to_Native(struct LevelInfo *);
@@ -56,6 +56,8 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *);
 void LoadTapeFromFilename(char *);
 void LoadTape(int);
 void LoadSolutionTape(int);
+void LoadScoreTape(char *, int);
+void LoadScoreCacheTape(char *, int);
 void SaveTapeToFilename(char *);
 void SaveTape(int);
 void SaveScoreTape(int);
@@ -73,6 +75,8 @@ void SaveServerScoreFromFile(int, boolean, char *);
 
 void LoadLocalAndServerScore(int, boolean);
 
+void PrepareScoreTapesForUpload(char *);
+
 void LoadUserNames(void);
 
 void LoadSetupFromFilename(char *);
@@ -98,9 +102,13 @@ void removeHideSetupEntry(void *);
 boolean hideSetupEntry(void *);
 
 void LoadCustomElementDescriptions(void);
+void InitMenuDesignSettings_FromHash(SetupFileHash *, boolean);
 void InitMenuDesignSettings_Static(void);
 void LoadMenuDesignSettings(void);
 void LoadMenuDesignSettings_AfterGraphics(void);
+void InitSoundSettings_FromHash(SetupFileHash *, boolean);
+void InitSoundSettings_Static(void);
+void LoadSoundSettings(void);
 void LoadUserDefinedEditorElementList(int **, int *);
 void LoadMusicInfo(void);
 void LoadHelpAnimInfo(void);
index 89e9e7fac1c739df6326eb4276d28913d6794795..831ec9010a5a0a4a9460d471bb8aaf2574b53045 100644 (file)
 // game panel display and control definitions
 #define GAME_PANEL_LEVEL_NUMBER                        0
 #define GAME_PANEL_GEMS                                1
-#define GAME_PANEL_INVENTORY_COUNT             2
-#define GAME_PANEL_INVENTORY_FIRST_1           3
-#define GAME_PANEL_INVENTORY_FIRST_2           4
-#define GAME_PANEL_INVENTORY_FIRST_3           5
-#define GAME_PANEL_INVENTORY_FIRST_4           6
-#define GAME_PANEL_INVENTORY_FIRST_5           7
-#define GAME_PANEL_INVENTORY_FIRST_6           8
-#define GAME_PANEL_INVENTORY_FIRST_7           9
-#define GAME_PANEL_INVENTORY_FIRST_8           10
-#define GAME_PANEL_INVENTORY_LAST_1            11
-#define GAME_PANEL_INVENTORY_LAST_2            12
-#define GAME_PANEL_INVENTORY_LAST_3            13
-#define GAME_PANEL_INVENTORY_LAST_4            14
-#define GAME_PANEL_INVENTORY_LAST_5            15
-#define GAME_PANEL_INVENTORY_LAST_6            16
-#define GAME_PANEL_INVENTORY_LAST_7            17
-#define GAME_PANEL_INVENTORY_LAST_8            18
-#define GAME_PANEL_KEY_1                       19
-#define GAME_PANEL_KEY_2                       20
-#define GAME_PANEL_KEY_3                       21
-#define GAME_PANEL_KEY_4                       22
-#define GAME_PANEL_KEY_5                       23
-#define GAME_PANEL_KEY_6                       24
-#define GAME_PANEL_KEY_7                       25
-#define GAME_PANEL_KEY_8                       26
-#define GAME_PANEL_KEY_WHITE                   27
-#define GAME_PANEL_KEY_WHITE_COUNT             28
-#define GAME_PANEL_SCORE                       29
-#define GAME_PANEL_HIGHSCORE                   30
-#define GAME_PANEL_TIME                                31
-#define GAME_PANEL_TIME_HH                     32
-#define GAME_PANEL_TIME_MM                     33
-#define GAME_PANEL_TIME_SS                     34
-#define GAME_PANEL_TIME_ANIM                   35
-#define GAME_PANEL_HEALTH                      36
-#define GAME_PANEL_HEALTH_ANIM                 37
-#define GAME_PANEL_FRAME                       38
-#define GAME_PANEL_SHIELD_NORMAL               39
-#define GAME_PANEL_SHIELD_NORMAL_TIME          40
-#define GAME_PANEL_SHIELD_DEADLY               41
-#define GAME_PANEL_SHIELD_DEADLY_TIME          42
-#define GAME_PANEL_EXIT                                43
-#define GAME_PANEL_EMC_MAGIC_BALL              44
-#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH       45
-#define GAME_PANEL_LIGHT_SWITCH                        46
-#define GAME_PANEL_LIGHT_SWITCH_TIME           47
-#define GAME_PANEL_TIMEGATE_SWITCH             48
-#define GAME_PANEL_TIMEGATE_SWITCH_TIME                49
-#define GAME_PANEL_SWITCHGATE_SWITCH           50
-#define GAME_PANEL_EMC_LENSES                  51
-#define GAME_PANEL_EMC_LENSES_TIME             52
-#define GAME_PANEL_EMC_MAGNIFIER               53
-#define GAME_PANEL_EMC_MAGNIFIER_TIME          54
-#define GAME_PANEL_BALLOON_SWITCH              55
-#define GAME_PANEL_DYNABOMB_NUMBER             56
-#define GAME_PANEL_DYNABOMB_SIZE               57
-#define GAME_PANEL_DYNABOMB_POWER              58
-#define GAME_PANEL_PENGUINS                    59
-#define GAME_PANEL_SOKOBAN_OBJECTS             60
-#define GAME_PANEL_SOKOBAN_FIELDS              61
-#define GAME_PANEL_ROBOT_WHEEL                 62
-#define GAME_PANEL_CONVEYOR_BELT_1             63
-#define GAME_PANEL_CONVEYOR_BELT_2             64
-#define GAME_PANEL_CONVEYOR_BELT_3             65
-#define GAME_PANEL_CONVEYOR_BELT_4             66
-#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH      67
-#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH      68
-#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH      69
-#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH      70
-#define GAME_PANEL_MAGIC_WALL                  71
-#define GAME_PANEL_MAGIC_WALL_TIME             72
-#define GAME_PANEL_GRAVITY_STATE               73
-#define GAME_PANEL_GRAPHIC_1                   74
-#define GAME_PANEL_GRAPHIC_2                   75
-#define GAME_PANEL_GRAPHIC_3                   76
-#define GAME_PANEL_GRAPHIC_4                   77
-#define GAME_PANEL_GRAPHIC_5                   78
-#define GAME_PANEL_GRAPHIC_6                   79
-#define GAME_PANEL_GRAPHIC_7                   80
-#define GAME_PANEL_GRAPHIC_8                   81
-#define GAME_PANEL_ELEMENT_1                   82
-#define GAME_PANEL_ELEMENT_2                   83
-#define GAME_PANEL_ELEMENT_3                   84
-#define GAME_PANEL_ELEMENT_4                   85
-#define GAME_PANEL_ELEMENT_5                   86
-#define GAME_PANEL_ELEMENT_6                   87
-#define GAME_PANEL_ELEMENT_7                   88
-#define GAME_PANEL_ELEMENT_8                   89
-#define GAME_PANEL_ELEMENT_COUNT_1             90
-#define GAME_PANEL_ELEMENT_COUNT_2             91
-#define GAME_PANEL_ELEMENT_COUNT_3             92
-#define GAME_PANEL_ELEMENT_COUNT_4             93
-#define GAME_PANEL_ELEMENT_COUNT_5             94
-#define GAME_PANEL_ELEMENT_COUNT_6             95
-#define GAME_PANEL_ELEMENT_COUNT_7             96
-#define GAME_PANEL_ELEMENT_COUNT_8             97
-#define GAME_PANEL_CE_SCORE_1                  98
-#define GAME_PANEL_CE_SCORE_2                  99
-#define GAME_PANEL_CE_SCORE_3                  100
-#define GAME_PANEL_CE_SCORE_4                  101
-#define GAME_PANEL_CE_SCORE_5                  102
-#define GAME_PANEL_CE_SCORE_6                  103
-#define GAME_PANEL_CE_SCORE_7                  104
-#define GAME_PANEL_CE_SCORE_8                  105
-#define GAME_PANEL_CE_SCORE_1_ELEMENT          106
-#define GAME_PANEL_CE_SCORE_2_ELEMENT          107
-#define GAME_PANEL_CE_SCORE_3_ELEMENT          108
-#define GAME_PANEL_CE_SCORE_4_ELEMENT          109
-#define GAME_PANEL_CE_SCORE_5_ELEMENT          110
-#define GAME_PANEL_CE_SCORE_6_ELEMENT          111
-#define GAME_PANEL_CE_SCORE_7_ELEMENT          112
-#define GAME_PANEL_CE_SCORE_8_ELEMENT          113
-#define GAME_PANEL_PLAYER_NAME                 114
-#define GAME_PANEL_LEVEL_NAME                  115
-#define GAME_PANEL_LEVEL_AUTHOR                        116
-
-#define NUM_GAME_PANEL_CONTROLS                        117
+#define GAME_PANEL_GEMS_NEEDED                 2
+#define GAME_PANEL_GEMS_COLLECTED              3
+#define GAME_PANEL_GEMS_SCORE                  4
+#define GAME_PANEL_INVENTORY_COUNT             5
+#define GAME_PANEL_INVENTORY_FIRST_1           6
+#define GAME_PANEL_INVENTORY_FIRST_2           7
+#define GAME_PANEL_INVENTORY_FIRST_3           8
+#define GAME_PANEL_INVENTORY_FIRST_4           9
+#define GAME_PANEL_INVENTORY_FIRST_5           10
+#define GAME_PANEL_INVENTORY_FIRST_6           11
+#define GAME_PANEL_INVENTORY_FIRST_7           12
+#define GAME_PANEL_INVENTORY_FIRST_8           13
+#define GAME_PANEL_INVENTORY_LAST_1            14
+#define GAME_PANEL_INVENTORY_LAST_2            15
+#define GAME_PANEL_INVENTORY_LAST_3            16
+#define GAME_PANEL_INVENTORY_LAST_4            17
+#define GAME_PANEL_INVENTORY_LAST_5            18
+#define GAME_PANEL_INVENTORY_LAST_6            19
+#define GAME_PANEL_INVENTORY_LAST_7            20
+#define GAME_PANEL_INVENTORY_LAST_8            21
+#define GAME_PANEL_KEY_1                       22
+#define GAME_PANEL_KEY_2                       23
+#define GAME_PANEL_KEY_3                       24
+#define GAME_PANEL_KEY_4                       25
+#define GAME_PANEL_KEY_5                       26
+#define GAME_PANEL_KEY_6                       27
+#define GAME_PANEL_KEY_7                       28
+#define GAME_PANEL_KEY_8                       29
+#define GAME_PANEL_KEY_WHITE                   30
+#define GAME_PANEL_KEY_WHITE_COUNT             31
+#define GAME_PANEL_SCORE                       32
+#define GAME_PANEL_HIGHSCORE                   33
+#define GAME_PANEL_TIME                                34
+#define GAME_PANEL_TIME_HH                     35
+#define GAME_PANEL_TIME_MM                     36
+#define GAME_PANEL_TIME_SS                     37
+#define GAME_PANEL_TIME_ANIM                   38
+#define GAME_PANEL_HEALTH                      39
+#define GAME_PANEL_HEALTH_ANIM                 40
+#define GAME_PANEL_FRAME                       41
+#define GAME_PANEL_SHIELD_NORMAL               42
+#define GAME_PANEL_SHIELD_NORMAL_TIME          43
+#define GAME_PANEL_SHIELD_DEADLY               44
+#define GAME_PANEL_SHIELD_DEADLY_TIME          45
+#define GAME_PANEL_EXIT                                46
+#define GAME_PANEL_EMC_MAGIC_BALL              47
+#define GAME_PANEL_EMC_MAGIC_BALL_SWITCH       48
+#define GAME_PANEL_LIGHT_SWITCH                        49
+#define GAME_PANEL_LIGHT_SWITCH_TIME           50
+#define GAME_PANEL_TIMEGATE_SWITCH             51
+#define GAME_PANEL_TIMEGATE_SWITCH_TIME                52
+#define GAME_PANEL_SWITCHGATE_SWITCH           53
+#define GAME_PANEL_EMC_LENSES                  54
+#define GAME_PANEL_EMC_LENSES_TIME             55
+#define GAME_PANEL_EMC_MAGNIFIER               56
+#define GAME_PANEL_EMC_MAGNIFIER_TIME          57
+#define GAME_PANEL_BALLOON_SWITCH              58
+#define GAME_PANEL_DYNABOMB_NUMBER             59
+#define GAME_PANEL_DYNABOMB_SIZE               60
+#define GAME_PANEL_DYNABOMB_POWER              61
+#define GAME_PANEL_PENGUINS                    62
+#define GAME_PANEL_SOKOBAN_OBJECTS             63
+#define GAME_PANEL_SOKOBAN_FIELDS              64
+#define GAME_PANEL_ROBOT_WHEEL                 65
+#define GAME_PANEL_CONVEYOR_BELT_1             66
+#define GAME_PANEL_CONVEYOR_BELT_2             67
+#define GAME_PANEL_CONVEYOR_BELT_3             68
+#define GAME_PANEL_CONVEYOR_BELT_4             69
+#define GAME_PANEL_CONVEYOR_BELT_1_SWITCH      70
+#define GAME_PANEL_CONVEYOR_BELT_2_SWITCH      71
+#define GAME_PANEL_CONVEYOR_BELT_3_SWITCH      72
+#define GAME_PANEL_CONVEYOR_BELT_4_SWITCH      73
+#define GAME_PANEL_MAGIC_WALL                  74
+#define GAME_PANEL_MAGIC_WALL_TIME             75
+#define GAME_PANEL_GRAVITY_STATE               76
+#define GAME_PANEL_GRAPHIC_1                   77
+#define GAME_PANEL_GRAPHIC_2                   78
+#define GAME_PANEL_GRAPHIC_3                   79
+#define GAME_PANEL_GRAPHIC_4                   80
+#define GAME_PANEL_GRAPHIC_5                   81
+#define GAME_PANEL_GRAPHIC_6                   82
+#define GAME_PANEL_GRAPHIC_7                   83
+#define GAME_PANEL_GRAPHIC_8                   84
+#define GAME_PANEL_ELEMENT_1                   85
+#define GAME_PANEL_ELEMENT_2                   86
+#define GAME_PANEL_ELEMENT_3                   87
+#define GAME_PANEL_ELEMENT_4                   88
+#define GAME_PANEL_ELEMENT_5                   89
+#define GAME_PANEL_ELEMENT_6                   90
+#define GAME_PANEL_ELEMENT_7                   91
+#define GAME_PANEL_ELEMENT_8                   92
+#define GAME_PANEL_ELEMENT_COUNT_1             93
+#define GAME_PANEL_ELEMENT_COUNT_2             94
+#define GAME_PANEL_ELEMENT_COUNT_3             95
+#define GAME_PANEL_ELEMENT_COUNT_4             96
+#define GAME_PANEL_ELEMENT_COUNT_5             97
+#define GAME_PANEL_ELEMENT_COUNT_6             98
+#define GAME_PANEL_ELEMENT_COUNT_7             99
+#define GAME_PANEL_ELEMENT_COUNT_8             100
+#define GAME_PANEL_CE_SCORE_1                  101
+#define GAME_PANEL_CE_SCORE_2                  102
+#define GAME_PANEL_CE_SCORE_3                  103
+#define GAME_PANEL_CE_SCORE_4                  104
+#define GAME_PANEL_CE_SCORE_5                  105
+#define GAME_PANEL_CE_SCORE_6                  106
+#define GAME_PANEL_CE_SCORE_7                  107
+#define GAME_PANEL_CE_SCORE_8                  108
+#define GAME_PANEL_CE_SCORE_1_ELEMENT          109
+#define GAME_PANEL_CE_SCORE_2_ELEMENT          110
+#define GAME_PANEL_CE_SCORE_3_ELEMENT          111
+#define GAME_PANEL_CE_SCORE_4_ELEMENT          112
+#define GAME_PANEL_CE_SCORE_5_ELEMENT          113
+#define GAME_PANEL_CE_SCORE_6_ELEMENT          114
+#define GAME_PANEL_CE_SCORE_7_ELEMENT          115
+#define GAME_PANEL_CE_SCORE_8_ELEMENT          116
+#define GAME_PANEL_PLAYER_NAME                 117
+#define GAME_PANEL_LEVEL_NAME                  118
+#define GAME_PANEL_LEVEL_AUTHOR                        119
+
+#define NUM_GAME_PANEL_CONTROLS                        120
 
 struct GamePanelOrderInfo
 {
@@ -242,6 +245,21 @@ static struct GamePanelControlInfo game_panel_controls[] =
     &game.panel.gems,
     TYPE_INTEGER,
   },
+  {
+    GAME_PANEL_GEMS_NEEDED,
+    &game.panel.gems_needed,
+    TYPE_INTEGER,
+  },
+  {
+    GAME_PANEL_GEMS_COLLECTED,
+    &game.panel.gems_collected,
+    TYPE_INTEGER,
+  },
+  {
+    GAME_PANEL_GEMS_SCORE,
+    &game.panel.gems_score,
+    TYPE_INTEGER,
+  },
   {
     GAME_PANEL_INVENTORY_COUNT,
     &game.panel.inventory_count,
@@ -962,7 +980,7 @@ static struct GamePanelControlInfo game_panel_controls[] =
        ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Tile[x][y] == EL_DIAMOND)
 
 #define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                           \
-       ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Tile[x][y]))
+       ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_FOOD_DARK_YAMYAM(Tile[x][y]))
 
 #define PACMAN_CAN_ENTER_FIELD(e, x, y)                                        \
        ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Tile[x][y]))
@@ -1017,19 +1035,22 @@ static struct GamePanelControlInfo game_panel_controls[] =
 #define GAME_CTRL_ID_SAVE              5
 #define GAME_CTRL_ID_PAUSE2            6
 #define GAME_CTRL_ID_LOAD              7
-#define GAME_CTRL_ID_PANEL_STOP                8
-#define GAME_CTRL_ID_PANEL_PAUSE       9
-#define GAME_CTRL_ID_PANEL_PLAY                10
-#define GAME_CTRL_ID_TOUCH_STOP                11
-#define GAME_CTRL_ID_TOUCH_PAUSE       12
-#define SOUND_CTRL_ID_MUSIC            13
-#define SOUND_CTRL_ID_LOOPS            14
-#define SOUND_CTRL_ID_SIMPLE           15
-#define SOUND_CTRL_ID_PANEL_MUSIC      16
-#define SOUND_CTRL_ID_PANEL_LOOPS      17
-#define SOUND_CTRL_ID_PANEL_SIMPLE     18
-
-#define NUM_GAME_BUTTONS               19
+#define GAME_CTRL_ID_RESTART           8
+#define GAME_CTRL_ID_PANEL_STOP                9
+#define GAME_CTRL_ID_PANEL_PAUSE       10
+#define GAME_CTRL_ID_PANEL_PLAY                11
+#define GAME_CTRL_ID_PANEL_RESTART     12
+#define GAME_CTRL_ID_TOUCH_STOP                13
+#define GAME_CTRL_ID_TOUCH_PAUSE       14
+#define GAME_CTRL_ID_TOUCH_RESTART     15
+#define SOUND_CTRL_ID_MUSIC            16
+#define SOUND_CTRL_ID_LOOPS            17
+#define SOUND_CTRL_ID_SIMPLE           18
+#define SOUND_CTRL_ID_PANEL_MUSIC      19
+#define SOUND_CTRL_ID_PANEL_LOOPS      20
+#define SOUND_CTRL_ID_PANEL_SIMPLE     21
+
+#define NUM_GAME_BUTTONS               22
 
 
 // forward declaration for internal use
@@ -1058,7 +1079,10 @@ static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
 static void KillPlayerUnlessEnemyProtected(int, int);
 static void KillPlayerUnlessExplosionProtected(int, int);
 
+static void CheckNextToConditions(int, int);
+static void TestIfPlayerNextToCustomElement(int, int);
 static void TestIfPlayerTouchesCustomElement(int, int);
+static void TestIfElementNextToCustomElement(int, int);
 static void TestIfElementTouchesCustomElement(int, int);
 static void TestIfElementHitsCustomElement(int, int, int);
 
@@ -1066,9 +1090,9 @@ static void HandleElementChange(int, int, int);
 static void ExecuteCustomElementAction(int, int, int, int);
 static boolean ChangeElement(int, int, int, int);
 
-static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
+static boolean CheckTriggeredElementChangeExt(int, int, int, int, int, int, int);
 #define CheckTriggeredElementChange(x, y, e, ev)                       \
-       CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1)
+       CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
 #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s)         \
        CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
 #define CheckTriggeredElementChangeBySide(x, y, e, ev, s)              \
@@ -1551,6 +1575,14 @@ access_direction_list[] =
   { EL_UNDEFINED,                      MV_NONE                              }
 };
 
+static struct XY xy_topdown[] =
+{
+  {  0, -1 },
+  { -1,  0 },
+  { +1,  0 },
+  {  0, +1 }
+};
+
 static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
 
 #define IS_AUTO_CHANGING(e)    (element_info[e].has_change_event[CE_DELAY])
@@ -1773,7 +1805,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
       player->active = TRUE;
 
       // remove potentially duplicate players
-      if (StorePlayer[jx][jy] == Tile[x][y])
+      if (IN_LEV_FIELD(jx, jy) && StorePlayer[jx][jy] == Tile[x][y])
        StorePlayer[jx][jy] = 0;
 
       StorePlayer[x][y] = Tile[x][y];
@@ -1803,6 +1835,29 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
   }
 }
 
+static void InitFieldForEngine_RND(int x, int y)
+{
+  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);
+
+  Tile[x][y] = element;
+}
+
+static void InitFieldForEngine(int x, int y)
+{
+  if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
+    InitFieldForEngine_RND(x, y);
+}
+
 static void InitField(int x, int y, boolean init_game)
 {
   int element = Tile[x][y];
@@ -1834,15 +1889,15 @@ static void InitField(int x, int y, boolean init_game)
       break;
 
     case EL_STONEBLOCK:
-      if (x < lev_fieldx-1 && Tile[x+1][y] == EL_ACID)
+      if (x < lev_fieldx - 1 && Tile[x + 1][y] == EL_ACID)
        Tile[x][y] = EL_ACID_POOL_TOPLEFT;
-      else if (x > 0 && Tile[x-1][y] == EL_ACID)
+      else if (x > 0 && Tile[x - 1][y] == EL_ACID)
        Tile[x][y] = EL_ACID_POOL_TOPRIGHT;
-      else if (y > 0 && Tile[x][y-1] == EL_ACID_POOL_TOPLEFT)
+      else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPLEFT)
        Tile[x][y] = EL_ACID_POOL_BOTTOMLEFT;
-      else if (y > 0 && Tile[x][y-1] == EL_ACID)
+      else if (y > 0 && Tile[x][y - 1] == EL_ACID)
        Tile[x][y] = EL_ACID_POOL_BOTTOM;
-      else if (y > 0 && Tile[x][y-1] == EL_ACID_POOL_TOPRIGHT)
+      else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPRIGHT)
        Tile[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
       break;
 
@@ -2025,6 +2080,14 @@ static void InitField(int x, int y, boolean init_game)
 
        InitField(x, y, init_game);
       }
+      else if (IS_EMPTY_ELEMENT(element))
+      {
+       GfxElementEmpty[x][y] = element;
+       Tile[x][y] = EL_EMPTY;
+
+       if (element_info[element].use_gfx_element)
+         game.use_masked_elements = TRUE;
+      }
 
       break;
   }
@@ -2222,15 +2285,19 @@ static void UpdateGameControlValues(void)
   int i, k;
   int time = (game.LevelSolved ?
              game.LevelSolved_CountingTime :
+             level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+             game_bd.time_played :
              level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              game_em.lev->time :
              level.game_engine_type == GAME_ENGINE_TYPE_SP ?
              game_sp.time_played :
              level.game_engine_type == GAME_ENGINE_TYPE_MM ?
              game_mm.energy_left :
-             game.no_time_limit ? TimePlayed : TimeLeft);
+             game.no_level_time_limit ? TimePlayed : TimeLeft);
   int score = (game.LevelSolved ?
               game.LevelSolved_CountingScore :
+              level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+              game_bd.score :
               level.game_engine_type == GAME_ENGINE_TYPE_EM ?
               game_em.lev->score :
               level.game_engine_type == GAME_ENGINE_TYPE_SP ?
@@ -2238,14 +2305,25 @@ static void UpdateGameControlValues(void)
               level.game_engine_type == GAME_ENGINE_TYPE_MM ?
               game_mm.score :
               game.score);
-  int gems = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
+  int gems = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+             game_bd.gems_still_needed :
+             level.game_engine_type == GAME_ENGINE_TYPE_EM ?
              game_em.lev->gems_needed :
              level.game_engine_type == GAME_ENGINE_TYPE_SP ?
              game_sp.infotrons_still_needed :
              level.game_engine_type == GAME_ENGINE_TYPE_MM ?
              game_mm.kettles_still_needed :
              game.gems_still_needed);
-  int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
+  int gems_needed = level.gems_needed;
+  int gems_collected = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+                       game_bd.game->cave->diamonds_collected :
+                       gems_needed - gems);
+  int gems_score = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+                   game_bd.game->cave->diamond_value :
+                   level.score[SC_EMERALD]);
+  int exit_closed = (level.game_engine_type == GAME_ENGINE_TYPE_BD ?
+                    game_bd.gems_still_needed > 0 :
+                    level.game_engine_type == GAME_ENGINE_TYPE_EM ?
                     game_em.lev->gems_needed > 0 :
                     level.game_engine_type == GAME_ENGINE_TYPE_SP ?
                     game_sp.infotrons_still_needed > 0 :
@@ -2270,6 +2348,9 @@ static void UpdateGameControlValues(void)
   // used instead of "level_nr" (for network games)
   game_panel_controls[GAME_PANEL_LEVEL_NUMBER].value = levelset.level_nr;
   game_panel_controls[GAME_PANEL_GEMS].value = gems;
+  game_panel_controls[GAME_PANEL_GEMS_NEEDED].value = gems_needed;
+  game_panel_controls[GAME_PANEL_GEMS_COLLECTED].value = gems_collected;
+  game_panel_controls[GAME_PANEL_GEMS_SCORE].value = gems_score;
 
   game_panel_controls[GAME_PANEL_INVENTORY_COUNT].value = 0;
   for (i = 0; i < MAX_NUM_KEYS; i++)
@@ -2547,7 +2628,9 @@ static void UpdateGameControlValues(void)
        int element = gpc->value;
        int graphic = el2panelimg(element);
        int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
-                              sync_random_frame : INIT_GFX_RANDOM());
+                              sync_random_frame :
+                              graphic_info[graphic].anim_global_anim_sync ?
+                              getGlobalAnimSyncFrame() : INIT_GFX_RANDOM());
 
        if (gpc->value != gpc->last_value)
        {
@@ -2582,7 +2665,9 @@ static void UpdateGameControlValues(void)
        int last_anim_random_frame = gfx.anim_random_frame;
        int graphic = gpc->graphic;
        int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
-                              sync_random_frame : INIT_GFX_RANDOM());
+                              sync_random_frame :
+                              graphic_info[graphic].anim_global_anim_sync ?
+                              getGlobalAnimSyncFrame() : INIT_GFX_RANDOM());
 
        if (gpc->value != gpc->last_value)
        {
@@ -2660,7 +2745,7 @@ static void DisplayGameControlValues(void)
     if (PANEL_DEACTIVATED(pos))
       continue;
 
-    if (pos->class == get_hash_from_key("extra_panel_items") &&
+    if (pos->class == get_hash_from_string("extra_panel_items") &&
        !setup.prefer_extra_panel_items)
       continue;
 
@@ -2670,15 +2755,25 @@ static void DisplayGameControlValues(void)
     if (type == TYPE_INTEGER)
     {
       if (nr == GAME_PANEL_LEVEL_NUMBER ||
+         nr == GAME_PANEL_INVENTORY_COUNT ||
+         nr == GAME_PANEL_SCORE ||
+         nr == GAME_PANEL_HIGHSCORE ||
          nr == GAME_PANEL_TIME)
       {
        boolean use_dynamic_size = (size == -1 ? TRUE : FALSE);
 
        if (use_dynamic_size)           // use dynamic number of digits
        {
-         int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000);
-         int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3);
-         int size2 = size1 + 1;
+         int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 :
+                             nr == GAME_PANEL_INVENTORY_COUNT ||
+                             nr == GAME_PANEL_TIME ? 1000 : 100000);
+         int size_add = (nr == GAME_PANEL_LEVEL_NUMBER ||
+                         nr == GAME_PANEL_INVENTORY_COUNT ||
+                         nr == GAME_PANEL_TIME ? 1 : 2);
+         int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 :
+                      nr == GAME_PANEL_INVENTORY_COUNT ||
+                      nr == GAME_PANEL_TIME ? 3 : 5);
+         int size2 = size1 + size_add;
          int font1 = pos->font;
          int font2 = pos->font_alt;
 
@@ -2742,7 +2837,7 @@ static void DisplayGameControlValues(void)
       int width, height;
       int dst_x = PANEL_XPOS(pos);
       int dst_y = PANEL_YPOS(pos);
-      boolean skip = (pos->class == get_hash_from_key("mm_engine_only") &&
+      boolean skip = (pos->class == get_hash_from_string("mm_engine_only") &&
                      level.game_engine_type != GAME_ENGINE_TYPE_MM);
 
       if (graphic != IMG_UNDEFINED && !skip)
@@ -3062,6 +3157,9 @@ static void InitGameEngine(void)
   game_em.use_single_button =
     (game.engine_version > VERSION_IDENT(4,0,0,2));
 
+  game_em.use_push_delay =
+    (game.engine_version > VERSION_IDENT(4,3,7,1));
+
   game_em.use_snap_key_bug =
     (game.engine_version < VERSION_IDENT(4,0,1,0));
 
@@ -3162,6 +3260,17 @@ static void InitGameEngine(void)
     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
   }
 
+  // ---------- initialize if element can trigger global animations -----------
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[i];
+
+    ei->has_anim_event = FALSE;
+  }
+
+  InitGlobalAnimEventsForCustomElements();
+
   // ---------- initialize internal run-time variables ------------------------
 
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -3227,12 +3336,16 @@ static void InitGameEngine(void)
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
-      ei->change_page[j].actual_trigger_element = EL_EMPTY;
-      ei->change_page[j].actual_trigger_player = EL_EMPTY;
-      ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE;
-      ei->change_page[j].actual_trigger_side = CH_SIDE_NONE;
-      ei->change_page[j].actual_trigger_ce_value = 0;
-      ei->change_page[j].actual_trigger_ce_score = 0;
+      struct ElementChangeInfo *change = &ei->change_page[j];
+
+      change->actual_trigger_element = EL_EMPTY;
+      change->actual_trigger_player = EL_EMPTY;
+      change->actual_trigger_player_bits = CH_PLAYER_NONE;
+      change->actual_trigger_side = CH_SIDE_NONE;
+      change->actual_trigger_ce_value = 0;
+      change->actual_trigger_ce_score = 0;
+      change->actual_trigger_x = -1;
+      change->actual_trigger_y = -1;
     }
   }
 
@@ -3250,16 +3363,18 @@ static void InitGameEngine(void)
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
-      if (!ei->change_page[j].can_change_or_has_action)
+      struct ElementChangeInfo *change = &ei->change_page[j];
+
+      if (!change->can_change_or_has_action)
        continue;
 
-      if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION])
+      if (change->has_event[CE_BY_OTHER_ACTION])
       {
-       int trigger_element = ei->change_page[j].trigger_element;
+       int trigger_element = change->trigger_element;
 
        for (k = 0; k < NUM_CHANGE_EVENTS; k++)
        {
-         if (ei->change_page[j].has_event[k])
+         if (change->has_event[k])
          {
            if (IS_GROUP_ELEMENT(trigger_element))
            {
@@ -3426,8 +3541,9 @@ static void InitGameEngine(void)
      level.game_engine_type == GAME_ENGINE_TYPE_EM &&
      !setup.forced_scroll_delay           ? 0 :
      setup.scroll_delay                   ? setup.scroll_delay_value       : 0);
-  game.scroll_delay_value =
-    MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
+  if (game.forced_scroll_delay_value == -1)
+    game.scroll_delay_value =
+      MIN(MAX(MIN_SCROLL_DELAY, game.scroll_delay_value), MAX_SCROLL_DELAY);
 
   // ---------- initialize game engine snapshots ------------------------------
   for (i = 0; i < MAX_PLAYERS; i++)
@@ -3468,10 +3584,10 @@ static void InitGameEngine(void)
     {
       int element = EL_CUSTOM_START + i;
 
-      if (HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
-         HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ||
-         HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ||
-         HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X))
+      if (HAS_ANY_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X))
        game.use_mouse_actions = TRUE;
     }
   }
@@ -3540,7 +3656,7 @@ void InitGame(void)
   int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
   int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
   int fade_mask = REDRAW_FIELD;
-
+  boolean restarting = (game_status == GAME_MODE_PLAYING);
   boolean emulate_bd = TRUE;   // unless non-BOULDERDASH elements found
   boolean emulate_sp = TRUE;   // unless non-SUPAPLEX    elements found
   int initial_move_dir = MV_DOWN;
@@ -3552,7 +3668,18 @@ void InitGame(void)
   if (!game.restart_level)
     CloseDoor(DOOR_CLOSE_1);
 
-  SetGameStatus(GAME_MODE_PLAYING);
+  if (restarting)
+  {
+    // force fading out global animations displayed during game play
+    SetGameStatus(GAME_MODE_PSEUDO_RESTARTING);
+  }
+  else
+  {
+    SetGameStatus(GAME_MODE_PLAYING);
+
+    // do not cover screen before fading out when starting from main menu
+    game_bd.cover_screen = FALSE;
+  }
 
   if (level_editor_test_game)
     FadeSkipNextFadeOut();
@@ -3568,6 +3695,18 @@ void InitGame(void)
 
   FadeOut(fade_mask);
 
+  if (restarting)
+  {
+    // force restarting global animations displayed during game play
+    RestartGlobalAnimsByStatus(GAME_MODE_PSEUDO_RESTARTING);
+
+    // this is required for "transforming" fade modes like cross-fading
+    // (else global animations will be stopped, but not restarted here)
+    SetAnimStatusBeforeFading(GAME_MODE_PSEUDO_RESTARTING);
+
+    SetGameStatus(GAME_MODE_PLAYING);
+  }
+
   if (level_editor_test_game)
     FadeSkipNextFadeIn();
 
@@ -3659,7 +3798,8 @@ void InitGame(void)
 
     player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
 
-    player->actual_frame_counter = 0;
+    player->actual_frame_counter.count = 0;
+    player->actual_frame_counter.value = 1;
 
     player->step_counter = 0;
 
@@ -3765,6 +3905,8 @@ void InitGame(void)
   TimeFrames = 0;
   TimePlayed = 0;
   TimeLeft = level.time;
+
+  TapeTimeFrames = 0;
   TapeTime = 0;
 
   ScreenMovDir = MV_NONE;
@@ -3795,9 +3937,12 @@ void InitGame(void)
   game.LevelSolved_CountingScore = 0;
   game.LevelSolved_CountingHealth = 0;
 
+  game.RestartGameRequested = FALSE;
+
   game.panel.active = TRUE;
 
-  game.no_time_limit = (level.time == 0);
+  game.no_level_time_limit = (level.time == 0);
+  game.time_limit = (leveldir_current->time_limit && setup.time_limit);
 
   game.yamyam_content_nr = 0;
   game.robot_wheel_active = FALSE;
@@ -3832,7 +3977,8 @@ void InitGame(void)
 
   game.explosions_delayed = TRUE;
 
-  game.envelope_active = FALSE;
+  // special case: set custom artwork setting to initial value
+  game.use_masked_elements = game.use_masked_elements_initial;
 
   for (i = 0; i < NUM_BELTS; i++)
   {
@@ -3875,7 +4021,9 @@ void InitGame(void)
 
     GfxFrame[x][y] = 0;
     GfxRandom[x][y] = INIT_GFX_RANDOM();
+    GfxRandomStatic[x][y] = INIT_GFX_RANDOM();
     GfxElement[x][y] = EL_UNDEFINED;
+    GfxElementEmpty[x][y] = EL_EMPTY;
     GfxAction[x][y] = ACTION_DEFAULT;
     GfxDir[x][y] = MV_NONE;
     GfxRedraw[x][y] = GFX_REDRAW_NONE;
@@ -3883,6 +4031,8 @@ void InitGame(void)
 
   SCAN_PLAYFIELD(x, y)
   {
+    InitFieldForEngine(x, y);
+
     if (emulate_bd && !IS_BD_ELEMENT(Tile[x][y]))
       emulate_bd = FALSE;
     if (emulate_sp && !IS_SP_ELEMENT(Tile[x][y]))
@@ -3895,6 +4045,10 @@ void InitGame(void)
 
   InitBeltMovement();
 
+  // required if level does not contain any "empty space" element
+  if (element_info[EL_EMPTY].use_gfx_element)
+    game.use_masked_elements = TRUE;
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     struct PlayerInfo *player = &stored_player[i];
@@ -4369,8 +4523,17 @@ void InitGame(void)
     scroll_y = SCROLL_POSITION_Y(local_player->jy);
   }
 
+  if (game.forced_scroll_x != ARG_UNDEFINED_VALUE)
+    scroll_x = game.forced_scroll_x;
+  if (game.forced_scroll_y != ARG_UNDEFINED_VALUE)
+    scroll_y = game.forced_scroll_y;
+
   // !!! FIX THIS (START) !!!
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    InitGameEngine_BD();
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     InitGameEngine_EM();
   }
@@ -4459,10 +4622,9 @@ void InitGame(void)
   }
 
   game.restart_level = FALSE;
-  game.restart_game_message = NULL;
-
   game.request_active = FALSE;
-  game.request_active_or_moving = FALSE;
+  game.envelope_active = FALSE;
+  game.any_door_active = FALSE;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
     InitGameActions_MM();
@@ -4476,6 +4638,8 @@ void InitGame(void)
     if (setup.sound_music)
       PlayLevelMusic();
   }
+
+  SetPlayfieldMouseCursorEnabled(!game.use_mouse_actions);
 }
 
 void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y,
@@ -4698,14 +4862,14 @@ void InitAmoebaNr(int x, int y)
 
 static void LevelSolved_SetFinalGameValues(void)
 {
-  game.time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
+  game.time_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.time_played :
+                    game.no_level_time_limit ? TimePlayed : TimeLeft);
   game.score_time_final = (level.use_step_counter ? TimePlayed :
                           TimePlayed * FRAMES_PER_SECOND + TimeFrames);
 
-  game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
-                     game_em.lev->score :
-                     level.game_engine_type == GAME_ENGINE_TYPE_MM ?
-                     game_mm.score :
+  game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_BD ? game_bd.score :
+                     level.game_engine_type == GAME_ENGINE_TYPE_EM ? game_em.lev->score :
+                     level.game_engine_type == GAME_ENGINE_TYPE_MM ? game_mm.score :
                      game.score);
 
   game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
@@ -4739,10 +4903,37 @@ static void LevelSolved(void)
   game.LevelSolved = TRUE;
   game.GameOver = TRUE;
 
+  tape.solved = TRUE;
+
   // needed here to display correct panel values while player walks into exit
   LevelSolved_SetFinalGameValues();
 }
 
+static boolean AdvanceToNextLevel(void)
+{
+  if (setup.increment_levels &&
+      level_nr < leveldir_current->last_level &&
+      !network_playing)
+  {
+    level_nr++;                // advance to next level
+    TapeErase();       // start with empty tape
+
+    if (setup.auto_play_next_level)
+    {
+      scores.continue_playing = TRUE;
+      scores.next_level_nr = level_nr;
+
+      LoadLevel(level_nr);
+
+      SaveLevelSetup_SeriesInfo();
+    }
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 void GameWon(void)
 {
   static int time_count_steps;
@@ -4807,7 +4998,7 @@ void GameWon(void)
        time_final = 0;
        time_frames = time_frames_left;
       }
-      else if (game.no_time_limit && TimePlayed < time_final_max)
+      else if (game.no_level_time_limit && TimePlayed < time_final_max)
       {
        time_final = time_final_max;
        time_frames = time_frames_final_max - time_frames_played;
@@ -4817,7 +5008,13 @@ void GameWon(void)
 
       time_count_steps = MAX(1, ABS(time_final - time) / 100);
 
-      if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+      if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+      {
+       // keep previous values (final values already processed here)
+       time_final = time;
+       score_final = score;
+      }
+      else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
       {
        health_final = 0;
        score_final += health * time_score;
@@ -4828,7 +5025,8 @@ void GameWon(void)
     }
 
     // if not counting score after game, immediately update game panel values
-    if (level_editor_test_game || !setup.count_score_after_game)
+    if (level_editor_test_game || !setup.count_score_after_game ||
+       level.game_engine_type == GAME_ENGINE_TYPE_BD)
     {
       time = time_final;
       score = score_final;
@@ -4966,10 +5164,32 @@ void GameEnd(void)
   // used instead of "level_nr" (needed for network games)
   int last_level_nr = levelset.level_nr;
   boolean tape_saved = FALSE;
+  boolean game_over = checkGameFailed();
+
+  // Important note: This function is not only called after "GameWon()", but also after
+  // "game over" (if automatically asking for restarting the game is disabled in setup)
+
+  // do not handle game end if game over and automatically asking for game restart
+  if (game_over && setup.ask_on_game_over)
+  {
+    // (this is a special case: player pressed "return" key or fire button shortly before
+    // automatically asking to restart the game, so skip asking and restart right away)
+
+    CloseDoor(DOOR_CLOSE_1);
 
-  game.LevelSolved_GameEnd = TRUE;
+    StartGameActions(network.enabled, setup.autorecord, level.random_seed);
+
+    return;
+  }
 
-  if (game.LevelSolved_SaveTape)
+  // do not handle game end if request dialog is already active
+  if (checkRequestActive())
+    return;
+
+  if (game.LevelSolved)
+    game.LevelSolved_GameEnd = TRUE;
+
+  if (game.LevelSolved_SaveTape && !score_info_tape_play)
   {
     // make sure that request dialog to save tape does not open door again
     if (!global.use_envelope_request)
@@ -4985,7 +5205,7 @@ void GameEnd(void)
   // if no tape is to be saved, close both doors simultaneously
   CloseDoor(DOOR_CLOSE_ALL);
 
-  if (level_editor_test_game)
+  if (level_editor_test_game || score_info_tape_play)
   {
     SetGameStatus(GAME_MODE_MAIN);
 
@@ -4994,7 +5214,7 @@ void GameEnd(void)
     return;
   }
 
-  if (!game.LevelSolved_SaveScore)
+  if (!game.GamePlayed || (!game.LevelSolved_SaveScore && !level.bd_intermission))
   {
     SetGameStatus(GAME_MODE_MAIN);
 
@@ -5011,32 +5231,19 @@ void GameEnd(void)
   }
 
   // save score and score tape before potentially erasing tape below
-  NewHighScore(last_level_nr, tape_saved);
-
-  if (setup.increment_levels &&
-      level_nr < leveldir_current->last_level &&
-      !network_playing)
-  {
-    level_nr++;                // advance to next level
-    TapeErase();       // start with empty tape
-
-    if (setup.auto_play_next_level)
-    {
-      LoadLevel(level_nr);
+  if (game.LevelSolved_SaveScore)
+    NewHighScore(last_level_nr, tape_saved);
 
-      SaveLevelSetup_SeriesInfo();
-    }
-  }
+  // increment and load next level (if possible and not configured otherwise)
+  AdvanceToNextLevel();
 
-  if (scores.last_added >= 0 && setup.show_scores_after_game)
+  if (game.LevelSolved_SaveScore && scores.last_added >= 0 && setup.show_scores_after_game)
   {
     SetGameStatus(GAME_MODE_SCORES);
 
     DrawHallOfFame(last_level_nr);
   }
-  else if (setup.auto_play_next_level && setup.increment_levels &&
-          last_level_nr < leveldir_current->last_level &&
-          !network_playing)
+  else if (scores.continue_playing)
   {
     StartGameActions(network.enabled, setup.autorecord, level.random_seed);
   }
@@ -5076,7 +5283,15 @@ static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry,
     // (special case: historic score entries have an empty tape basename entry)
     if (strEqual(new_entry->tape_basename, entry->tape_basename) &&
        !strEqual(new_entry->tape_basename, UNDEFINED_FILENAME))
+    {
+      // add fields from server score entry not stored in local score entry
+      // (currently, this means setting platform, version and country fields;
+      // in rare cases, this may also correct an invalid score value, as
+      // historic scores might have been truncated to 16-bit values locally)
+      *entry = *new_entry;
+
       return -1;
+    }
 
     if (is_better || entry_is_empty)
     {
@@ -5116,7 +5331,8 @@ static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry,
     }
   }
 
-  return -1;
+  // special case: new score is beyond the last high score list position
+  return MAX_SCORE_ENTRIES;
 }
 
 void NewHighScore(int level_nr, boolean tape_saved)
@@ -5134,19 +5350,50 @@ void NewHighScore(int level_nr, boolean tape_saved)
 
   scores.last_added = addScoreEntry(&scores, &new_entry, one_per_name);
 
-  if (scores.last_added >= 0)
+  if (scores.last_added >= MAX_SCORE_ENTRIES)
   {
-    SaveScore(level_nr);
+    scores.last_added = MAX_SCORE_ENTRIES - 1;
+    scores.force_last_added = TRUE;
+
+    scores.entry[scores.last_added] = new_entry;
 
     // store last added local score entry (before merging server scores)
     scores.last_added_local = scores.last_added;
+
+    return;
   }
 
-  if (game.LevelSolved_SaveTape)
+  if (scores.last_added < 0)
+    return;
+
+  SaveScore(level_nr);
+
+  // store last added local score entry (before merging server scores)
+  scores.last_added_local = scores.last_added;
+
+  if (!game.LevelSolved_SaveTape)
+    return;
+
+  SaveScoreTape(level_nr);
+
+  if (setup.ask_for_using_api_server)
   {
-    SaveScoreTape(level_nr);
-    SaveServerScore(level_nr, tape_saved);
+    setup.use_api_server =
+      Request("Upload your score and tape to the high score server?", REQ_ASK);
+
+    if (!setup.use_api_server)
+      Request("Not using high score server! Use setup menu to enable again!",
+             REQ_CONFIRM);
+
+    runtime.use_api_server = setup.use_api_server;
+
+    // after asking for using API server once, do not ask again
+    setup.ask_for_using_api_server = FALSE;
+
+    SaveSetup_ServerSetup();
   }
+
+  SaveServerScore(level_nr, tape_saved);
 }
 
 void MergeServerScore(void)
@@ -5224,6 +5471,8 @@ static void ResetGfxFrame(int x, int y)
 
   if (graphic_info[graphic].anim_global_sync)
     GfxFrame[x][y] = FrameCounter;
+  else if (graphic_info[graphic].anim_global_anim_sync)
+    GfxFrame[x][y] = getGlobalAnimSyncFrame();
   else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
     GfxFrame[x][y] = CustomValue[x][y];
   else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
@@ -5303,17 +5552,9 @@ void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
 
 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
 {
-  int oldx = x, oldy = y;
   int direction = MovDir[x][y];
-
-  if (direction == MV_LEFT)
-    oldx++;
-  else if (direction == MV_RIGHT)
-    oldx--;
-  else if (direction == MV_UP)
-    oldy++;
-  else if (direction == MV_DOWN)
-    oldy--;
+  int oldx = x + (direction & MV_LEFT ? +1 : direction & MV_RIGHT ? -1 : 0);
+  int oldy = y + (direction & MV_UP   ? +1 : direction & MV_DOWN  ? -1 : 0);
 
   *comes_from_x = oldx;
   *comes_from_y = oldy;
@@ -5328,16 +5569,17 @@ static int MovingOrBlocked2Element(int x, int y)
     int oldx, oldy;
 
     Blocked2Moving(x, y, &oldx, &oldy);
+
     return Tile[oldx][oldy];
   }
-  else
-    return element;
+
+  return element;
 }
 
 static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
 {
   // like MovingOrBlocked2Element(), but if element is moving
-  // and (x,y) is the field the moving element is just leaving,
+  // and (x, y) is the field the moving element is just leaving,
   // return EL_BLOCKED instead of the element value
   int element = Tile[x][y];
 
@@ -5452,7 +5694,7 @@ void DrawDynamite(int x, int y)
   else if (game.use_masked_elements)
     DrawLevelElement(x, y, EL_EMPTY);
 
-  frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+  frame = getGraphicAnimationFrameXY(graphic, x, y);
 
   if (Back[x][y] || Store[x][y] || game.use_masked_elements)
     DrawGraphicThruMask(sx, sy, graphic, frame);
@@ -5530,7 +5772,7 @@ static void setScreenCenteredToAllPlayers(int *sx, int *sy)
   *sy = (sy1 + sy2) / 2;
 }
 
-static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir,
+static void DrawRelocateScreen(int old_x, int old_y, int x, int y,
                               boolean center_screen, boolean quick_relocation)
 {
   unsigned int frame_delay_value_old = GetVideoFrameDelay();
@@ -5560,14 +5802,47 @@ static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir,
   {
     // relocation _without_ centering of screen
 
-    int center_scroll_x = SCROLL_POSITION_X(old_x);
-    int center_scroll_y = SCROLL_POSITION_Y(old_y);
-    int offset_x = x + (scroll_x - center_scroll_x);
-    int offset_y = y + (scroll_y - center_scroll_y);
+    // apply distance between old and new player position to scroll position
+    int shifted_scroll_x = scroll_x + (x - old_x);
+    int shifted_scroll_y = scroll_y + (y - old_y);
+
+    // make sure that shifted scroll position does not scroll beyond screen
+    new_scroll_x = SCROLL_POSITION_X(shifted_scroll_x + MIDPOSX);
+    new_scroll_y = SCROLL_POSITION_Y(shifted_scroll_y + MIDPOSY);
+
+    // special case for teleporting from one end of the playfield to the other
+    // (this kludge prevents the destination area to be shifted by half a tile
+    // against the source destination for even screen width or screen height;
+    // probably most useful when used with high "game.forced_scroll_delay_value"
+    // in combination with "game.forced_scroll_x" and "game.forced_scroll_y")
+    if (quick_relocation)
+    {
+      if (EVEN(SCR_FIELDX))
+      {
+       // relocate (teleport) between left and right border (half or full)
+       if (scroll_x == SBX_Left && new_scroll_x == SBX_Right - 1)
+         new_scroll_x = SBX_Right;
+       else if (scroll_x == SBX_Left + 1 && new_scroll_x == SBX_Right)
+         new_scroll_x = SBX_Right - 1;
+       else if (scroll_x == SBX_Right && new_scroll_x == SBX_Left + 1)
+         new_scroll_x = SBX_Left;
+       else if (scroll_x == SBX_Right - 1 && new_scroll_x == SBX_Left)
+         new_scroll_x = SBX_Left + 1;
+      }
 
-    // for new screen position, apply previous offset to center position
-    new_scroll_x = SCROLL_POSITION_X(offset_x);
-    new_scroll_y = SCROLL_POSITION_Y(offset_y);
+      if (EVEN(SCR_FIELDY))
+      {
+       // relocate (teleport) between top and bottom border (half or full)
+       if (scroll_y == SBY_Upper && new_scroll_y == SBY_Lower - 1)
+         new_scroll_y = SBY_Lower;
+       else if (scroll_y == SBY_Upper + 1 && new_scroll_y == SBY_Lower)
+         new_scroll_y = SBY_Lower - 1;
+       else if (scroll_y == SBY_Lower && new_scroll_y == SBY_Upper + 1)
+         new_scroll_y = SBY_Upper;
+       else if (scroll_y == SBY_Lower - 1 && new_scroll_y == SBY_Upper)
+         new_scroll_y = SBY_Upper + 1;
+      }
+    }
   }
 
   if (quick_relocation)
@@ -5701,7 +5976,7 @@ static void RelocatePlayer(int jx, int jy, int el_player_raw)
   }
 
   // only visually relocate centered player
-  DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir,
+  DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy,
                     FALSE, level.instant_relocation);
 
   TestIfPlayerTouchesBadThing(jx, jy);
@@ -5734,9 +6009,6 @@ static void Explode(int ex, int ey, int phase, int mode)
   int last_phase;
   int border_element;
 
-  // !!! eliminate this variable !!!
-  int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
-
   if (game.explosions_delayed)
   {
     ExplodeField[ex][ey] = mode;
@@ -5746,6 +6018,8 @@ static void Explode(int ex, int ey, int phase, int mode)
   if (phase == EX_PHASE_START)         // initialize 'Store[][]' field
   {
     int center_element = Tile[ex][ey];
+    int ce_value = CustomValue[ex][ey];
+    int ce_score = element_info[center_element].collect_score;
     int artwork_element, explosion_element;    // set these values later
 
     // remove things displayed in background while burning dynamite
@@ -5884,6 +6158,14 @@ static void Explode(int ex, int ey, int phase, int mode)
       else
        Store[x][y] = EL_EMPTY;
 
+      if (IS_CUSTOM_ELEMENT(center_element))
+       Store[x][y] = (Store[x][y] == EL_CURRENT_CE_VALUE ? ce_value :
+                      Store[x][y] == EL_CURRENT_CE_SCORE ? ce_score :
+                      Store[x][y] >= EL_PREV_CE_8 &&
+                      Store[x][y] <= EL_NEXT_CE_8 ?
+                      RESOLVED_REFERENCE_ELEMENT(center_element, Store[x][y]) :
+                      Store[x][y]);
+
       if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
          center_element == EL_AMOEBA_TO_DIAMOND)
        Store2[x][y] = element;
@@ -5957,6 +6239,10 @@ static void Explode(int ex, int ey, int phase, int mode)
       return;
   }
 
+  // this can happen if the player was just killed by an explosion
+  if (GfxElement[x][y] == EL_UNDEFINED)
+    GfxElement[x][y] = EL_EMPTY;
+
   if (phase == last_phase)
   {
     int element;
@@ -6011,9 +6297,9 @@ static void Explode(int ex, int ey, int phase, int mode)
   else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
     int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
-    int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+    int frame = getGraphicAnimationFrameXY(graphic, x, y);
 
-    if (phase == delay)
+    if (phase == 1)
       TEST_DrawLevelFieldCrumbled(x, y);
 
     if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
@@ -6023,11 +6309,11 @@ static void Explode(int ex, int ey, int phase, int mode)
     }
     else if (IS_WALKABLE_UNDER(Back[x][y]))
     {
-      DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+      DrawLevelGraphic(x, y, graphic, frame);
       DrawLevelElementThruMask(x, y, Back[x][y]);
     }
     else if (!IS_WALKABLE_INSIDE(Back[x][y]))
-      DrawScreenGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+      DrawLevelGraphic(x, y, graphic, frame);
   }
 }
 
@@ -6038,13 +6324,7 @@ static void DynaExplode(int ex, int ey)
   int dynabomb_size = 1;
   boolean dynabomb_xl = FALSE;
   struct PlayerInfo *player;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   if (IS_ACTIVE_BOMB(dynabomb_element))
   {
@@ -6060,8 +6340,8 @@ static void DynaExplode(int ex, int ey)
   {
     for (j = 1; j <= dynabomb_size; j++)
     {
-      int x = ex + j * xy[i][0];
-      int y = ey + j * xy[i][1];
+      int x = ex + j * xy[i].x;
+      int y = ey + j * xy[i].y;
       int element;
 
       if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Tile[x][y]))
@@ -6342,7 +6622,7 @@ static void ToggleBeltSwitch(int x, int y)
   }
 }
 
-static void ToggleSwitchgateSwitch(int x, int y)
+static void ToggleSwitchgateSwitch(void)
 {
   int xx, yy;
 
@@ -6822,7 +7102,7 @@ static void Impact(int x, int y)
                 smashed == EL_DC_SWITCHGATE_SWITCH_UP ||
                 smashed == EL_DC_SWITCHGATE_SWITCH_DOWN)
        {
-         ToggleSwitchgateSwitch(x, y + 1);
+         ToggleSwitchgateSwitch();
        }
        else if (smashed == EL_LIGHT_SWITCH ||
                 smashed == EL_LIGHT_SWITCH_ACTIVE)
@@ -7196,18 +7476,12 @@ static void TurnRoundExt(int x, int y)
     if (element == EL_PENGUIN)
     {
       int i;
-      static int xy[4][2] =
-      {
-       { 0, -1 },
-       { -1, 0 },
-       { +1, 0 },
-       { 0, +1 }
-      };
+      struct XY *xy = xy_topdown;
 
       for (i = 0; i < NUM_DIRECTIONS; i++)
       {
-       int ex = x + xy[i][0];
-       int ey = y + xy[i][1];
+       int ex = x + xy[i].x;
+       int ey = y + xy[i].y;
 
        if (IN_LEV_FIELD(ex, ey) && (Tile[ex][ey] == EL_EXIT_OPEN ||
                                     Tile[ex][ey] == EL_EM_EXIT_OPEN ||
@@ -7451,7 +7725,7 @@ static void TurnRoundExt(int x, int y)
     boolean can_turn_left =
       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
     boolean can_turn_right =
-      CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+      CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y);
 
     if (element_info[element].move_stepsize == 0)      // "not moving"
       return;
@@ -7606,25 +7880,13 @@ static void TurnRoundExt(int x, int y)
   }
   else if (move_pattern & MV_MAZE_RUNNER_STYLE)
   {
-    static int test_xy[7][2] =
-    {
-      { 0, -1 },
-      { -1, 0 },
-      { +1, 0 },
-      { 0, +1 },
-      { 0, -1 },
-      { -1, 0 },
-      { +1, 0 },
-    };
-    static int test_dir[7] =
+    struct XY *test_xy = xy_topdown;
+    static int test_dir[4] =
     {
       MV_UP,
       MV_LEFT,
       MV_RIGHT,
-      MV_DOWN,
-      MV_UP,
-      MV_LEFT,
-      MV_RIGHT,
+      MV_DOWN
     };
     boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
     int move_preference = -1000000;    // start with very low preference
@@ -7634,11 +7896,12 @@ static void TurnRoundExt(int x, int y)
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int move_dir = test_dir[start_test + i];
+      int j = (start_test + i) % 4;
+      int move_dir = test_dir[j];
       int move_dir_preference;
 
-      xx = x + test_xy[start_test + i][0];
-      yy = y + test_xy[start_test + i][1];
+      xx = x + test_xy[j].x;
+      yy = y + test_xy[j].y;
 
       if (hunter_mode && IN_LEV_FIELD(xx, yy) &&
          (IS_PLAYER(xx, yy) || Tile[xx][yy] == EL_PLAYER_IS_LEAVING))
@@ -8200,7 +8463,7 @@ static void StartMoving(int x, int y)
                       dir == MV_RIGHT  ? IMG_FLAMES_1_RIGHT :
                       dir == MV_UP     ? IMG_FLAMES_1_UP :
                       dir == MV_DOWN   ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
-       int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+       int frame = getGraphicAnimationFrameXY(graphic, x, y);
 
        GfxAction[x][y] = ACTION_ATTACKING;
 
@@ -8238,7 +8501,7 @@ static void StartMoving(int x, int y)
            if (IN_SCR_FIELD(sx, sy))
            {
              TEST_DrawLevelFieldCrumbled(xx, yy);
-             DrawGraphic(sx, sy, flame_graphic, frame);
+             DrawScreenGraphic(sx, sy, flame_graphic, frame);
            }
          }
          else
@@ -8292,7 +8555,7 @@ static void StartMoving(int x, int y)
 
        PlayLevelSound(newx, newy, SND_PENGUIN_PASSING);
        if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
-         DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
+         DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2img(element), 0);
 
        game.friends_still_needed--;
        if (!game.friends_still_needed &&
@@ -8304,7 +8567,7 @@ static void StartMoving(int x, int y)
       }
       else if (IS_FOOD_PENGUIN(Tile[newx][newy]))
       {
-       if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
+       if (DigField(local_player, x, y, newx, newy, 0, 0, DF_DIG) == MP_MOVING)
          TEST_DrawLevelField(newx, newy);
        else
          GfxDir[x][y] = MovDir[x][y] = MV_NONE;
@@ -8387,6 +8650,9 @@ static void StartMoving(int x, int y)
          GfxDir[x][y] = diagonal_move_dir;
          ChangeDelay[x][y] = change_delay;
 
+         if (Store[x][y] == EL_EMPTY)
+           Store[x][y] = GfxElementEmpty[x][y];
+
          graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
                                   GfxDir[x][y]);
 
@@ -8606,7 +8872,7 @@ void ContinueMoving(int x, int y)
 
   if (pushed_by_player)                // special case: moving object pushed by player
   {
-    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
+    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x, y)->MovPos));
   }
   else if (use_step_delay)     // special case: moving object has step delay
   {
@@ -8868,7 +9134,7 @@ void ContinueMoving(int x, int y)
 
     CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
                               player->index_bit, push_side);
-    CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X,
+    CheckTriggeredElementChangeByPlayer(newx, newy, element, CE_PLAYER_PUSHES_X,
                                        player->index_bit, push_side);
   }
 
@@ -8893,18 +9159,12 @@ int AmoebaNeighbourNr(int ax, int ay)
   int i;
   int element = Tile[ax][ay];
   int group_nr = 0;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int x = ax + xy[i][0];
-    int y = ay + xy[i][1];
+    int x = ax + xy[i].x;
+    int y = ay + xy[i].y;
 
     if (!IN_LEV_FIELD(x, y))
       continue;
@@ -8920,21 +9180,15 @@ static void AmoebaMerge(int ax, int ay)
 {
   int i, x, y, xx, yy;
   int new_group_nr = AmoebaNr[ax][ay];
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   if (new_group_nr == 0)
     return;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    x = ax + xy[i][0];
-    y = ay + xy[i][1];
+    x = ax + xy[i].x;
+    y = ay + xy[i].y;
 
     if (!IN_LEV_FIELD(x, y))
       continue;
@@ -8997,18 +9251,12 @@ void AmoebaToDiamond(int ax, int ay)
   }
   else
   {
-    static int xy[4][2] =
-    {
-      { 0, -1 },
-      { -1, 0 },
-      { +1, 0 },
-      { 0, +1 }
-    };
+    struct XY *xy = xy_topdown;
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      x = ax + xy[i][0];
-      y = ay + xy[i][1];
+      x = ax + xy[i].x;
+      y = ay + xy[i].y;
 
       if (!IN_LEV_FIELD(x, y))
        continue;
@@ -9063,17 +9311,16 @@ static void AmoebaToDiamondBD(int ax, int ay, int new_element)
 
 static void AmoebaGrowing(int x, int y)
 {
-  static unsigned int sound_delay = 0;
-  static unsigned int sound_delay_value = 0;
+  static DelayCounter sound_delay = { 0 };
 
   if (!MovDelay[x][y])         // start new growing cycle
   {
     MovDelay[x][y] = 7;
 
-    if (DelayReached(&sound_delay, sound_delay_value))
+    if (DelayReached(&sound_delay))
     {
       PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
-      sound_delay_value = 30;
+      sound_delay.value = 30;
     }
   }
 
@@ -9085,7 +9332,7 @@ static void AmoebaGrowing(int x, int y)
       int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
                                           6 - MovDelay[x][y]);
 
-      DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
+      DrawLevelGraphic(x, y, IMG_AMOEBA_GROWING, frame);
     }
 
     if (!MovDelay[x][y])
@@ -9099,15 +9346,14 @@ static void AmoebaGrowing(int x, int y)
 
 static void AmoebaShrinking(int x, int y)
 {
-  static unsigned int sound_delay = 0;
-  static unsigned int sound_delay_value = 0;
+  static DelayCounter sound_delay = { 0 };
 
   if (!MovDelay[x][y])         // start new shrinking cycle
   {
     MovDelay[x][y] = 7;
 
-    if (DelayReached(&sound_delay, sound_delay_value))
-      sound_delay_value = 30;
+    if (DelayReached(&sound_delay))
+      sound_delay.value = 30;
   }
 
   if (MovDelay[x][y])          // wait some time before shrinking
@@ -9118,7 +9364,7 @@ static void AmoebaShrinking(int x, int y)
       int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
                                           6 - MovDelay[x][y]);
 
-      DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
+      DrawLevelGraphic(x, y, IMG_AMOEBA_SHRINKING, frame);
     }
 
     if (!MovDelay[x][y])
@@ -9140,13 +9386,7 @@ static void AmoebaReproduce(int ax, int ay)
   int graphic = el2img(element);
   int newax = ax, neway = ay;
   boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER);
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   if (!level.amoeba_speed && element != EL_EMC_DRIPPER)
   {
@@ -9171,8 +9411,8 @@ static void AmoebaReproduce(int ax, int ay)
   if (can_drop)                        // EL_AMOEBA_WET or EL_EMC_DRIPPER
   {
     int start = RND(4);
-    int x = ax + xy[start][0];
-    int y = ay + xy[start][1];
+    int x = ax + xy[start].x;
+    int y = ay + xy[start].y;
 
     if (!IN_LEV_FIELD(x, y))
       return;
@@ -9197,8 +9437,8 @@ static void AmoebaReproduce(int ax, int ay)
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
       int j = (start + i) % 4;
-      int x = ax + xy[j][0];
-      int y = ay + xy[j][1];
+      int x = ax + xy[j].x;
+      int y = ay + xy[j].y;
 
       if (!IN_LEV_FIELD(x, y))
        continue;
@@ -9318,7 +9558,7 @@ static void Life(int ax, int ay)
 
   for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++)
   {
-    int xx = ax+x1, yy = ay+y1;
+    int xx = ax + x1, yy = ay + y1;
     int old_element = Tile[xx][yy];
     int num_neighbours = 0;
 
@@ -9327,7 +9567,7 @@ static void Life(int ax, int ay)
 
     for (y2 = -1; y2 < 2; y2++) for (x2 = -1; x2 < 2; x2++)
     {
-      int x = xx+x2, y = yy+y2;
+      int x = xx + x2, y = yy + y2;
 
       if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
        continue;
@@ -9372,7 +9612,7 @@ static void Life(int ax, int ay)
          num_neighbours <= life_parameter[3])
       {
        Tile[xx][yy] = element;
-       MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
+       MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time - 1);
        if (Tile[xx][yy] != old_element)
          TEST_DrawLevelField(xx, yy);
        Stop[xx][yy] = TRUE;
@@ -9620,7 +9860,7 @@ static void DrawTwinkleOnField(int x, int y)
   }
 }
 
-static void MauerWaechst(int x, int y)
+static void WallGrowing(int x, int y)
 {
   int delay = 6;
 
@@ -9636,7 +9876,7 @@ static void MauerWaechst(int x, int y)
       int graphic = el_dir2img(Tile[x][y], GfxDir[x][y]);
       int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
 
-      DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+      DrawLevelGraphic(x, y, graphic, frame);
     }
 
     if (!MovDelay[x][y])
@@ -9670,15 +9910,59 @@ static void MauerWaechst(int x, int y)
   }
 }
 
-static void MauerAbleger(int ax, int ay)
+static void CheckWallGrowing(int ax, int ay)
 {
   int element = Tile[ax][ay];
   int graphic = el2img(element);
-  boolean oben_frei = FALSE, unten_frei = FALSE;
-  boolean links_frei = FALSE, rechts_frei = FALSE;
-  boolean oben_massiv = FALSE, unten_massiv = FALSE;
-  boolean links_massiv = FALSE, rechts_massiv = FALSE;
-  boolean new_wall = FALSE;
+  boolean free_top    = FALSE;
+  boolean free_bottom = FALSE;
+  boolean free_left   = FALSE;
+  boolean free_right  = FALSE;
+  boolean stop_top    = FALSE;
+  boolean stop_bottom = FALSE;
+  boolean stop_left   = FALSE;
+  boolean stop_right  = FALSE;
+  boolean new_wall    = FALSE;
+
+  boolean is_steelwall  = (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+                          element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
+                          element == EL_EXPANDABLE_STEELWALL_ANY);
+
+  boolean grow_vertical   = (element == EL_EXPANDABLE_WALL_VERTICAL ||
+                            element == EL_EXPANDABLE_WALL_ANY ||
+                            element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
+                            element == EL_EXPANDABLE_STEELWALL_ANY);
+
+  boolean grow_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+                            element == EL_EXPANDABLE_WALL_ANY ||
+                            element == EL_EXPANDABLE_WALL ||
+                            element == EL_BD_EXPANDABLE_WALL ||
+                            element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+                            element == EL_EXPANDABLE_STEELWALL_ANY);
+
+  boolean stop_vertical   = (element == EL_EXPANDABLE_WALL_VERTICAL ||
+                            element == EL_EXPANDABLE_STEELWALL_VERTICAL);
+
+  boolean stop_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+                            element == EL_EXPANDABLE_WALL ||
+                            element == EL_EXPANDABLE_STEELWALL_HORIZONTAL);
+
+  int wall_growing = (is_steelwall ?
+                     EL_EXPANDABLE_STEELWALL_GROWING :
+                     EL_EXPANDABLE_WALL_GROWING);
+
+  int gfx_wall_growing_up    = (is_steelwall ?
+                               IMG_EXPANDABLE_STEELWALL_GROWING_UP :
+                               IMG_EXPANDABLE_WALL_GROWING_UP);
+  int gfx_wall_growing_down  = (is_steelwall ?
+                               IMG_EXPANDABLE_STEELWALL_GROWING_DOWN :
+                               IMG_EXPANDABLE_WALL_GROWING_DOWN);
+  int gfx_wall_growing_left  = (is_steelwall ?
+                               IMG_EXPANDABLE_STEELWALL_GROWING_LEFT :
+                               IMG_EXPANDABLE_WALL_GROWING_LEFT);
+  int gfx_wall_growing_right = (is_steelwall ?
+                               IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT :
+                               IMG_EXPANDABLE_WALL_GROWING_RIGHT);
 
   if (IS_ANIMATED(graphic))
     DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
@@ -9693,188 +9977,84 @@ static void MauerAbleger(int ax, int ay)
       return;
   }
 
-  if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
-    oben_frei = TRUE;
-  if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
-    unten_frei = TRUE;
-  if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
-    links_frei = TRUE;
-  if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
-    rechts_frei = TRUE;
+  if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1))
+    free_top = TRUE;
+  if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1))
+    free_bottom = TRUE;
+  if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay))
+    free_left = TRUE;
+  if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay))
+    free_right = TRUE;
 
-  if (element == EL_EXPANDABLE_WALL_VERTICAL ||
-      element == EL_EXPANDABLE_WALL_ANY)
+  if (grow_vertical)
   {
-    if (oben_frei)
-    {
-      Tile[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
-      Store[ax][ay-1] = element;
-      GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
-      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
-                   IMG_EXPANDABLE_WALL_GROWING_UP, 0);
-      new_wall = TRUE;
-    }
-    if (unten_frei)
+    if (free_top)
     {
-      Tile[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
-      Store[ax][ay+1] = element;
-      GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
-      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
-                   IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
-      new_wall = TRUE;
-    }
-  }
+      Tile[ax][ay - 1] = wall_growing;
+      Store[ax][ay - 1] = element;
+      GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP;
 
-  if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
-      element == EL_EXPANDABLE_WALL_ANY ||
-      element == EL_EXPANDABLE_WALL ||
-      element == EL_BD_EXPANDABLE_WALL)
-  {
-    if (links_frei)
-    {
-      Tile[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
-      Store[ax-1][ay] = element;
-      GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
-      if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
-                   IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
-      new_wall = TRUE;
-    }
+      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1)))
+       DrawLevelGraphic(ax, ay - 1, gfx_wall_growing_up, 0);
 
-    if (rechts_frei)
-    {
-      Tile[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
-      Store[ax+1][ay] = element;
-      GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
-      if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
-                   IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
       new_wall = TRUE;
     }
-  }
-
-  if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
-    TEST_DrawLevelField(ax, ay);
-
-  if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Tile[ax][ay-1]))
-    oben_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Tile[ax][ay+1]))
-    unten_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Tile[ax-1][ay]))
-    links_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Tile[ax+1][ay]))
-    rechts_massiv = TRUE;
-
-  if (((oben_massiv && unten_massiv) ||
-       element == EL_EXPANDABLE_WALL_HORIZONTAL ||
-       element == EL_EXPANDABLE_WALL) &&
-      ((links_massiv && rechts_massiv) ||
-       element == EL_EXPANDABLE_WALL_VERTICAL))
-    Tile[ax][ay] = EL_WALL;
-
-  if (new_wall)
-    PlayLevelSoundAction(ax, ay, ACTION_GROWING);
-}
-
-static void MauerAblegerStahl(int ax, int ay)
-{
-  int element = Tile[ax][ay];
-  int graphic = el2img(element);
-  boolean oben_frei = FALSE, unten_frei = FALSE;
-  boolean links_frei = FALSE, rechts_frei = FALSE;
-  boolean oben_massiv = FALSE, unten_massiv = FALSE;
-  boolean links_massiv = FALSE, rechts_massiv = FALSE;
-  boolean new_wall = FALSE;
-
-  if (IS_ANIMATED(graphic))
-    DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
 
-  if (!MovDelay[ax][ay])       // start building new wall
-    MovDelay[ax][ay] = 6;
-
-  if (MovDelay[ax][ay])                // wait some time before building new wall
-  {
-    MovDelay[ax][ay]--;
-    if (MovDelay[ax][ay])
-      return;
-  }
+    if (free_bottom)
+    {
+      Tile[ax][ay + 1] = wall_growing;
+      Store[ax][ay + 1] = element;
+      GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN;
 
-  if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
-    oben_frei = TRUE;
-  if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
-    unten_frei = TRUE;
-  if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
-    links_frei = TRUE;
-  if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
-    rechts_frei = TRUE;
+      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1)))
+       DrawLevelGraphic(ax, ay + 1, gfx_wall_growing_down, 0);
 
-  if (element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
-      element == EL_EXPANDABLE_STEELWALL_ANY)
-  {
-    if (oben_frei)
-    {
-      Tile[ax][ay-1] = EL_EXPANDABLE_STEELWALL_GROWING;
-      Store[ax][ay-1] = element;
-      GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
-      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
-                   IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0);
-      new_wall = TRUE;
-    }
-    if (unten_frei)
-    {
-      Tile[ax][ay+1] = EL_EXPANDABLE_STEELWALL_GROWING;
-      Store[ax][ay+1] = element;
-      GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
-      if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
-                   IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0);
       new_wall = TRUE;
     }
   }
 
-  if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
-      element == EL_EXPANDABLE_STEELWALL_ANY)
+  if (grow_horizontal)
   {
-    if (links_frei)
+    if (free_left)
     {
-      Tile[ax-1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
-      Store[ax-1][ay] = element;
-      GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
-      if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
-                   IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0);
+      Tile[ax - 1][ay] = wall_growing;
+      Store[ax - 1][ay] = element;
+      GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT;
+
+      if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay)))
+       DrawLevelGraphic(ax - 1, ay, gfx_wall_growing_left, 0);
+
       new_wall = TRUE;
     }
 
-    if (rechts_frei)
+    if (free_right)
     {
-      Tile[ax+1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
-      Store[ax+1][ay] = element;
-      GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
-      if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
-                   IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0);
+      Tile[ax + 1][ay] = wall_growing;
+      Store[ax + 1][ay] = element;
+      GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT;
+
+      if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay)))
+       DrawLevelGraphic(ax + 1, ay, gfx_wall_growing_right, 0);
+
       new_wall = TRUE;
     }
   }
 
-  if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Tile[ax][ay-1]))
-    oben_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Tile[ax][ay+1]))
-    unten_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Tile[ax-1][ay]))
-    links_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Tile[ax+1][ay]))
-    rechts_massiv = TRUE;
+  if (element == EL_EXPANDABLE_WALL && (free_left || free_right))
+    TEST_DrawLevelField(ax, ay);
+
+  if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1]))
+    stop_top = TRUE;
+  if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1]))
+    stop_bottom = TRUE;
+  if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay]))
+    stop_left = TRUE;
+  if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay]))
+    stop_right = TRUE;
 
-  if (((oben_massiv && unten_massiv) ||
-       element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) &&
-      ((links_massiv && rechts_massiv) ||
-       element == EL_EXPANDABLE_STEELWALL_VERTICAL))
-    Tile[ax][ay] = EL_STEELWALL;
+  if (((stop_top && stop_bottom) || stop_horizontal) &&
+      ((stop_left && stop_right) || stop_vertical))
+    Tile[ax][ay] = (is_steelwall ? EL_STEELWALL : EL_WALL);
 
   if (new_wall)
     PlayLevelSoundAction(ax, ay, ACTION_GROWING);
@@ -9884,19 +10064,14 @@ static void CheckForDragon(int x, int y)
 {
   int i, j;
   boolean dragon_found = FALSE;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     for (j = 0; j < 4; j++)
     {
-      int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
+      int xx = x + j * xy[i].x;
+      int yy = y + j * xy[i].y;
 
       if (IN_LEV_FIELD(xx, yy) &&
          (Tile[xx][yy] == EL_FLAMES || Tile[xx][yy] == EL_DRAGON))
@@ -9915,8 +10090,9 @@ static void CheckForDragon(int x, int y)
     {
       for (j = 0; j < 3; j++)
       {
-       int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
-  
+       int xx = x + j * xy[i].x;
+       int yy = y + j * xy[i].y;
+
        if (IN_LEV_FIELD(xx, yy) && Tile[xx][yy] == EL_FLAMES)
        {
          Tile[xx][yy] = EL_EMPTY;
@@ -9946,18 +10122,12 @@ static void InitBuggyBase(int x, int y)
 static void WarnBuggyBase(int x, int y)
 {
   int i;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
 
     if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
     {
@@ -10160,7 +10330,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page)
 
        DisplayGameControlValues();
 
-       if (!TimeLeft && setup.time_limit)
+       if (!TimeLeft && game.time_limit)
          for (i = 0; i < MAX_PLAYERS; i++)
            KillPlayer(&stored_player[i]);
       }
@@ -10632,17 +10802,26 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change)
 
     if (GFX_CRUMBLED(new_element))
       TEST_DrawLevelFieldCrumbledNeighbours(x, y);
-  }
 
-  // check if element under the player changes from accessible to unaccessible
-  // (needed for special case of dropping element which then changes)
-  // (must be checked after creating new element for walkable group elements)
-  if (IS_PLAYER(x, y) && !player_explosion_protected &&
-      IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
-  {
-    Bang(x, y);
+    if (old_element == EL_EXPLOSION)
+    {
+      Store[x][y] = Store2[x][y] = 0;
 
-    return;
+      // check if new element replaces an exploding player, requiring cleanup
+      if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
+       StorePlayer[x][y] = 0;
+    }
+
+    // check if element under the player changes from accessible to unaccessible
+    // (needed for special case of dropping element which then changes)
+    // (must be checked after creating new element for walkable group elements)
+    if (IS_PLAYER(x, y) && !player_explosion_protected &&
+       IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
+    {
+      KillPlayer(PLAYERINFO(x, y));
+
+      return;
+    }
   }
 
   // "ChangeCount" not set yet to allow "entered by player" change one time
@@ -10702,6 +10881,8 @@ static boolean ChangeElement(int x, int y, int element, int page)
     change->actual_trigger_side = CH_SIDE_NONE;
     change->actual_trigger_ce_value = 0;
     change->actual_trigger_ce_score = 0;
+    change->actual_trigger_x = -1;
+    change->actual_trigger_y = -1;
   }
 
   // do not change elements more than a specified maximum number of changes
@@ -10710,6 +10891,11 @@ static boolean ChangeElement(int x, int y, int element, int page)
 
   ChangeCount[x][y]++;         // count number of changes in the same frame
 
+  if (ei->has_anim_event)
+    HandleGlobalAnimEventByElementChange(element, page, x, y,
+                                        change->actual_trigger_x,
+                                        change->actual_trigger_y);
+
   if (change->explode)
   {
     Bang(x, y);
@@ -10944,13 +11130,14 @@ static void HandleElementChange(int x, int y, int page)
 
   if (ChangeDelay[x][y] != 0)          // continue element change
   {
-    if (change->can_change)
-    {
-      int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+    int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
 
-      if (IS_ANIMATED(graphic))
-       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+    // also needed if CE can not change, but has CE delay with CE action
+    if (IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
+    if (change->can_change)
+    {
       if (change->change_function)
        change->change_function(x, y);
     }
@@ -11037,6 +11224,8 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y,
        change->actual_trigger_side = trigger_side;
        change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y];
        change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
+       change->actual_trigger_x = trigger_x;
+       change->actual_trigger_y = trigger_y;
 
        if ((change->can_change && !change_done) || change->has_action)
        {
@@ -11132,7 +11321,8 @@ static boolean CheckElementChangeExt(int x, int y,
        different to element changes that affect other elements to change on the
        whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */
     boolean check_trigger_element =
-      (trigger_event == CE_TOUCHING_X ||
+      (trigger_event == CE_NEXT_TO_X ||
+       trigger_event == CE_TOUCHING_X ||
        trigger_event == CE_HITTING_X ||
        trigger_event == CE_HIT_BY_X ||
        trigger_event == CE_DIGGING_X); // this one was forgotten until 3.2.3
@@ -11150,6 +11340,8 @@ static boolean CheckElementChangeExt(int x, int y,
       change->actual_trigger_side = trigger_side;
       change->actual_trigger_ce_value = CustomValue[x][y];
       change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
+      change->actual_trigger_x = x;
+      change->actual_trigger_y = y;
 
       // special case: trigger element not at (x,y) position for some events
       if (check_trigger_element)
@@ -11173,6 +11365,8 @@ static boolean CheckElementChangeExt(int x, int y,
 
        change->actual_trigger_ce_value = CustomValue[xx][yy];
        change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
+       change->actual_trigger_x = xx;
+       change->actual_trigger_y = yy;
       }
 
       if (change->can_change && !change_done)
@@ -11512,7 +11706,22 @@ static void SetTapeActionFromMouseAction(byte *tape_action,
 
 static void CheckLevelSolved(void)
 {
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    if (game_bd.level_solved &&
+       !game_bd.game_over)                             // game won
+    {
+      LevelSolved();
+
+      game_bd.game_over = TRUE;
+
+      game.all_players_gone = TRUE;
+    }
+
+    if (game_bd.game_over)                             // game lost
+      game.all_players_gone = TRUE;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     if (game_em.level_solved &&
        !game_em.game_over)                             // game won
@@ -11559,14 +11768,78 @@ static void CheckLevelSolved(void)
   }
 }
 
+static void PlayTimeoutSound(int seconds_left)
+{
+  // will be played directly by BD engine (for classic bonus time sounds)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD && checkBonusTime_BD())
+    return;
+
+  // try to use individual "running out of time" sound for each second left
+  int sound = SND_GAME_RUNNING_OUT_OF_TIME_0 - seconds_left;
+
+  // if special sound per second not defined, use default sound
+  if (getSoundInfoEntryFilename(sound) == NULL)
+    sound = SND_GAME_RUNNING_OUT_OF_TIME;
+
+  // if out of time, but player still alive, play special "timeout" sound, if defined
+  if (seconds_left == 0 && !checkGameFailed())
+    if (getSoundInfoEntryFilename(SND_GAME_TIMEOUT) != NULL)
+      sound = SND_GAME_TIMEOUT;
+
+  PlaySound(sound);
+}
+
+static void CheckLevelTime_StepCounter(void)
+{
+  int i;
+
+  TimePlayed++;
+
+  if (TimeLeft > 0)
+  {
+    TimeLeft--;
+
+    if (TimeLeft <= 10 && game.time_limit && !game.LevelSolved)
+      PlayTimeoutSound(TimeLeft);
+
+    game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
+
+    DisplayGameControlValues();
+
+    if (!TimeLeft && game.time_limit && !game.LevelSolved)
+      for (i = 0; i < MAX_PLAYERS; i++)
+       KillPlayer(&stored_player[i]);
+  }
+  else if (game.no_level_time_limit && !game.all_players_gone)
+  {
+    game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
+
+    DisplayGameControlValues();
+  }
+}
+
 static void CheckLevelTime(void)
 {
+  int frames_per_second = FRAMES_PER_SECOND;
   int i;
 
-  if (TimeFrames >= FRAMES_PER_SECOND)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    // level time may be running slower in native BD engine
+    frames_per_second = getFramesPerSecond_BD();
+
+    // if native engine time changed, force main engine time change
+    if (getTimeLeft_BD() < TimeLeft)
+      TimeFrames = frames_per_second;
+
+    // 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 (TimeFrames >= frames_per_second)
   {
     TimeFrames = 0;
-    TapeTime++;
 
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -11589,30 +11862,45 @@ static void CheckLevelTime(void)
       {
        TimeLeft--;
 
-       if (TimeLeft <= 10 && setup.time_limit)
-         PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
+       if (TimeLeft <= 10 && game.time_limit)
+         PlayTimeoutSound(TimeLeft);
 
        /* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value
           is reset from other values in UpdateGameDoorValues() -- FIX THIS */
 
        game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
 
-       if (!TimeLeft && setup.time_limit)
+       if (!TimeLeft && game.time_limit)
        {
-         if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+         if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+         {
+           if (game_bd.game->cave->player_state == GD_PL_LIVING)
+             game_bd.game->cave->player_state = GD_PL_TIMEOUT;
+         }
+         else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+         {
            game_em.lev->killed_out_of_time = TRUE;
+         }
          else
+         {
            for (i = 0; i < MAX_PLAYERS; i++)
              KillPlayer(&stored_player[i]);
+         }
        }
       }
-      else if (game.no_time_limit && !game.all_players_gone)
+      else if (game.no_level_time_limit && !game.all_players_gone)
       {
        game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
       }
 
-      game_em.lev->time = (game.no_time_limit ? TimePlayed : TimeLeft);
+      game_em.lev->time = (game.no_level_time_limit ? TimePlayed : TimeLeft);
     }
+  }
+
+  if (TapeTimeFrames >= FRAMES_PER_SECOND)
+  {
+    TapeTimeFrames = 0;
+    TapeTime++;
 
     if (tape.recording || tape.playing)
       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
@@ -11628,8 +11916,21 @@ void AdvanceFrameAndPlayerCounters(int player_nr)
 {
   int i;
 
-  // advance frame counters (global frame counter and time frame counter)
+  // handle game and tape time differently for native BD game engine
+
+  // tape time is running in native BD engine even if player is not hatched yet
+  if (!checkGameRunning())
+    return;
+
+  // advance frame counters (global frame counter and tape time frame counter)
   FrameCounter++;
+  TapeTimeFrames++;
+
+  // level time is running in native BD engine after player is being hatched
+  if (!checkGamePlaying())
+    return;
+
+  // advance time frame counter (used to control available time to solve level)
   TimeFrames++;
 
   // advance player counters (counters for move delay, move animation etc.)
@@ -11673,6 +11974,64 @@ void AdvanceFrameAndPlayerCounters(int player_nr)
   }
 }
 
+void AdvanceFrameCounter(void)
+{
+  FrameCounter++;
+}
+
+void AdvanceGfxFrame(void)
+{
+  int x, y;
+
+  SCAN_PLAYFIELD(x, y)
+  {
+    GfxFrame[x][y]++;
+  }
+}
+
+static void HandleMouseAction(struct MouseActionInfo *mouse_action,
+                             struct MouseActionInfo *mouse_action_last)
+{
+  if (mouse_action->button)
+  {
+    int new_button = (mouse_action->button && mouse_action_last->button == 0);
+    int ch_button = CH_SIDE_FROM_BUTTON(mouse_action->button);
+    int x = mouse_action->lx;
+    int y = mouse_action->ly;
+    int element = Tile[x][y];
+
+    if (new_button)
+    {
+      CheckElementChangeByMouse(x, y, element, CE_CLICKED_BY_MOUSE, ch_button);
+      CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_CLICKED_ON_X,
+                                        ch_button);
+    }
+
+    CheckElementChangeByMouse(x, y, element, CE_PRESSED_BY_MOUSE, ch_button);
+    CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_PRESSED_ON_X,
+                                      ch_button);
+
+    if (level.use_step_counter)
+    {
+      boolean counted_click = FALSE;
+
+      // element clicked that can change when clicked/pressed
+      if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+         (HAS_ANY_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+          HAS_ANY_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE)))
+       counted_click = TRUE;
+
+      // element clicked that can trigger change when clicked/pressed
+      if (trigger_events[element][CE_MOUSE_CLICKED_ON_X] ||
+         trigger_events[element][CE_MOUSE_PRESSED_ON_X])
+       counted_click = TRUE;
+
+      if (new_button && counted_click)
+       CheckLevelTime_StepCounter();
+    }
+  }
+}
+
 void StartGameActions(boolean init_network_game, boolean record_tape,
                      int random_seed)
 {
@@ -11681,6 +12040,9 @@ void StartGameActions(boolean init_network_game, boolean record_tape,
   if (record_tape)
     TapeStartRecording(new_random_seed);
 
+  if (setup.auto_pause_on_start && !tape.pausing)
+    TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
   if (init_network_game)
   {
     SendToServer_LevelFile();
@@ -11713,7 +12075,7 @@ static void GameActionsExt(void)
     Warn("element '%s' caused endless loop in game engine",
         EL_NAME(recursion_loop_element));
 
-    RequestQuitGameExt(FALSE, level_editor_test_game, message);
+    RequestQuitGameExt(program.headless, level_editor_test_game, message);
 
     recursion_loop_detected = FALSE;   // if game should be continued
 
@@ -11865,7 +12227,7 @@ static void GameActionsExt(void)
     TapeRecordAction(tape_action);
 
   // remember if game was played (especially after tape stopped playing)
-  if (!tape.playing && summarized_player_action)
+  if (!tape.playing && summarized_player_action && !checkGameFailed())
     game.GamePlayed = TRUE;
 
 #if USE_NEW_PLAYER_ASSIGNMENTS
@@ -11918,7 +12280,11 @@ static void GameActionsExt(void)
     game.snapshot.last_action[i] = stored_player[i].effective_action;
   }
 
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    GameActions_BD_Main();
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
     GameActions_EM_Main();
   }
@@ -11985,28 +12351,37 @@ void GameActions(void)
   GameActions_CheckSaveEngineSnapshot();
 }
 
+void GameActions_BD_Main(void)
+{
+  byte effective_action[MAX_PLAYERS];
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    effective_action[i] = stored_player[i].effective_action;
+
+  GameActions_BD(effective_action);
+}
+
 void GameActions_EM_Main(void)
 {
   byte effective_action[MAX_PLAYERS];
-  boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
   int i;
 
   for (i = 0; i < MAX_PLAYERS; i++)
     effective_action[i] = stored_player[i].effective_action;
 
-  GameActions_EM(effective_action, warp_mode);
+  GameActions_EM(effective_action);
 }
 
 void GameActions_SP_Main(void)
 {
   byte effective_action[MAX_PLAYERS];
-  boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
   int i;
 
   for (i = 0; i < MAX_PLAYERS; i++)
     effective_action[i] = stored_player[i].effective_action;
 
-  GameActions_SP(effective_action, warp_mode);
+  GameActions_SP(effective_action);
 
   for (i = 0; i < MAX_PLAYERS; i++)
   {
@@ -12019,9 +12394,9 @@ void GameActions_SP_Main(void)
 
 void GameActions_MM_Main(void)
 {
-  boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
+  AdvanceGfxFrame();
 
-  GameActions_MM(local_player->effective_mouse_action, warp_mode);
+  GameActions_MM(local_player->effective_mouse_action);
 }
 
 void GameActions_RND_Main(void)
@@ -12085,7 +12460,7 @@ void GameActions_RND(void)
     game.centered_player_nr = game.centered_player_nr_next;
     game.set_centered_player = FALSE;
 
-    DrawRelocateScreen(0, 0, sx, sy, MV_NONE, TRUE, setup.quick_switch);
+    DrawRelocateScreen(0, 0, sx, sy, TRUE, setup.quick_switch);
     DrawGameDoorValues();
   }
 
@@ -12238,26 +12613,7 @@ void GameActions_RND(void)
 #endif
   }
 
-  if (mouse_action.button)
-  {
-    int new_button = (mouse_action.button && mouse_action_last.button == 0);
-    int ch_button = CH_SIDE_FROM_BUTTON(mouse_action.button);
-
-    x = mouse_action.lx;
-    y = mouse_action.ly;
-    element = Tile[x][y];
-
-    if (new_button)
-    {
-      CheckElementChangeByMouse(x, y, element, CE_CLICKED_BY_MOUSE, ch_button);
-      CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_CLICKED_ON_X,
-                                        ch_button);
-    }
-
-    CheckElementChangeByMouse(x, y, element, CE_PRESSED_BY_MOUSE, ch_button);
-    CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_PRESSED_ON_X,
-                                      ch_button);
-  }
+  HandleMouseAction(&mouse_action, &mouse_action_last);
 
   SCAN_PLAYFIELD(x, y)
   {
@@ -12265,6 +12621,9 @@ void GameActions_RND(void)
     graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
     last_gfx_frame = GfxFrame[x][y];
 
+    if (element == EL_EMPTY)
+      graphic = el2img(GfxElementEmpty[x][y]);
+
     ResetGfxFrame(x, y);
 
     if (GfxFrame[x][y] != last_gfx_frame && !Stop[x][y])
@@ -12298,6 +12657,8 @@ void GameActions_RND(void)
       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
     }
 
+    CheckNextToConditions(x, y);
+
     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
     {
       StartMoving(x, y);
@@ -12358,17 +12719,16 @@ void GameActions_RND(void)
       CheckExitSP(x, y);
     else if (element == EL_EXPANDABLE_WALL_GROWING ||
             element == EL_EXPANDABLE_STEELWALL_GROWING)
-      MauerWaechst(x, y);
+      WallGrowing(x, y);
     else if (element == EL_EXPANDABLE_WALL ||
             element == EL_EXPANDABLE_WALL_HORIZONTAL ||
             element == EL_EXPANDABLE_WALL_VERTICAL ||
             element == EL_EXPANDABLE_WALL_ANY ||
-            element == EL_BD_EXPANDABLE_WALL)
-      MauerAbleger(x, y);
-    else if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+            element == EL_BD_EXPANDABLE_WALL ||
+            element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
             element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
             element == EL_EXPANDABLE_STEELWALL_ANY)
-      MauerAblegerStahl(x, y);
+      CheckWallGrowing(x, y);
     else if (element == EL_FLAMES)
       CheckForDragon(x, y);
     else if (element == EL_EXPLOSION)
@@ -12377,7 +12737,7 @@ void GameActions_RND(void)
             element == EL_DIAGONAL_SHRINKING ||
             element == EL_DIAGONAL_GROWING)
     {
-      graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]);
+      graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y], GfxDir[x][y]);
 
       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
     }
@@ -12422,7 +12782,7 @@ void GameActions_RND(void)
       y = RND(lev_fieldy);
       element = Tile[x][y];
 
-      if (!IS_PLAYER(x,y) &&
+      if (!IS_PLAYER(x, y) &&
          (element == EL_EMPTY ||
           CAN_GROW_INTO(element) ||
           element == EL_QUICKSAND_EMPTY ||
@@ -12430,10 +12790,10 @@ void GameActions_RND(void)
           element == EL_ACID_SPLASH_LEFT ||
           element == EL_ACID_SPLASH_RIGHT))
       {
-       if ((IN_LEV_FIELD(x, y-1) && Tile[x][y-1] == EL_AMOEBA_WET) ||
-           (IN_LEV_FIELD(x-1, y) && Tile[x-1][y] == EL_AMOEBA_WET) ||
-           (IN_LEV_FIELD(x+1, y) && Tile[x+1][y] == EL_AMOEBA_WET) ||
-           (IN_LEV_FIELD(x, y+1) && Tile[x][y+1] == EL_AMOEBA_WET))
+       if ((IN_LEV_FIELD(x, y - 1) && Tile[x][y - 1] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x - 1, y) && Tile[x - 1][y] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x + 1, y) && Tile[x + 1][y] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x, y + 1) && Tile[x][y + 1] == EL_AMOEBA_WET))
          Tile[x][y] = EL_AMOEBA_DROP;
       }
 
@@ -12798,7 +13158,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
       !AllPlayersInSight(player, new_jx, new_jy))
     return MP_NO_ACTION;
 
-  can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
+  can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx, real_dy, DF_DIG);
   if (can_move != MP_MOVING)
     return can_move;
 
@@ -13071,7 +13431,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
 
   if (mode == SCROLL_INIT)
   {
-    player->actual_frame_counter = FrameCounter;
+    player->actual_frame_counter.count = FrameCounter;
     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
     if ((player->block_last_field || player->block_delay_adjustment > 0) &&
@@ -13100,7 +13460,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
     if (player->MovPos != 0)   // player has not yet reached destination
       return;
   }
-  else if (!FrameReached(&player->actual_frame_counter, 1))
+  else if (!FrameReached(&player->actual_frame_counter))
     return;
 
   if (player->MovPos != 0)
@@ -13129,9 +13489,6 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       }
     }
 
-    player->last_jx = jx;
-    player->last_jy = jy;
-
     if (Tile[jx][jy] == EL_EXIT_OPEN ||
        Tile[jx][jy] == EL_EM_EXIT_OPEN ||
        Tile[jx][jy] == EL_EM_EXIT_OPENING ||
@@ -13149,6 +13506,9 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
        LevelSolved();
     }
 
+    player->last_jx = jx;
+    player->last_jy = jy;
+
     // this breaks one level: "machine", level 000
     {
       int move_direction = player->MovDir;
@@ -13168,13 +13528,18 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
                                          CE_PLAYER_LEAVES_X,
                                          player->index_bit, leave_side);
 
-      if (IS_CUSTOM_ELEMENT(new_element))
-       CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
-                                  player->index_bit, enter_side);
+      // needed because pushed element has not yet reached its destination,
+      // so it would trigger a change event at its previous field location
+      if (!player->is_pushing)
+      {
+       if (IS_CUSTOM_ELEMENT(new_element))
+         CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
+                                    player->index_bit, enter_side);
 
-      CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
-                                         CE_PLAYER_ENTERS_X,
-                                         player->index_bit, enter_side);
+       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
+                                           CE_PLAYER_ENTERS_X,
+                                           player->index_bit, enter_side);
+      }
 
       CheckTriggeredElementChangeBySide(jx, jy, player->initial_element,
                                        CE_MOVE_OF_X, move_direction);
@@ -13185,8 +13550,8 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       TestIfPlayerTouchesBadThing(jx, jy);
       TestIfPlayerTouchesCustomElement(jx, jy);
 
-      /* needed because pushed element has not yet reached its destination,
-        so it would trigger a change event at its previous field location */
+      // needed because pushed element has not yet reached its destination,
+      // so it would trigger a change event at its previous field location
       if (!player->is_pushing)
        TestIfElementTouchesCustomElement(jx, jy);      // for empty space
 
@@ -13210,33 +13575,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
     }
 
     if (level.use_step_counter)
-    {
-      int i;
-
-      TimePlayed++;
-
-      if (TimeLeft > 0)
-      {
-       TimeLeft--;
-
-       if (TimeLeft <= 10 && setup.time_limit && !game.LevelSolved)
-         PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
-
-       game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
-
-       DisplayGameControlValues();
-
-       if (!TimeLeft && setup.time_limit && !game.LevelSolved)
-         for (i = 0; i < MAX_PLAYERS; i++)
-           KillPlayer(&stored_player[i]);
-      }
-      else if (game.no_time_limit && !game.all_players_gone)
-      {
-       game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
-
-       DisplayGameControlValues();
-      }
-    }
+      CheckLevelTime_StepCounter();
 
     if (tape.single_step && tape.recording && !tape.pausing &&
        !player->programmed_action)
@@ -13249,20 +13588,22 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
 
 void ScrollScreen(struct PlayerInfo *player, int mode)
 {
-  static unsigned int screen_frame_counter = 0;
+  static DelayCounter screen_frame_counter = { 0 };
 
   if (mode == SCROLL_INIT)
   {
     // set scrolling step size according to actual player's moving speed
     ScrollStepSize = TILEX / player->move_delay_value;
 
-    screen_frame_counter = FrameCounter;
+    screen_frame_counter.count = FrameCounter;
+    screen_frame_counter.value = 1;
+
     ScreenMovDir = player->MovDir;
     ScreenMovPos = player->MovPos;
     ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
     return;
   }
-  else if (!FrameReached(&screen_frame_counter, 1))
+  else if (!FrameReached(&screen_frame_counter))
     return;
 
   if (ScreenMovPos)
@@ -13275,15 +13616,73 @@ void ScrollScreen(struct PlayerInfo *player, int mode)
     ScreenMovDir = MV_NONE;
 }
 
-void TestIfPlayerTouchesCustomElement(int x, int y)
+void CheckNextToConditions(int x, int y)
 {
-  static int xy[4][2] =
+  int element = Tile[x][y];
+
+  if (IS_PLAYER(x, y))
+    TestIfPlayerNextToCustomElement(x, y);
+
+  if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+      HAS_ANY_CHANGE_EVENT(element, CE_NEXT_TO_X))
+    TestIfElementNextToCustomElement(x, y);
+}
+
+void TestIfPlayerNextToCustomElement(int x, int y)
+{
+  struct XY *xy = xy_topdown;
+  static int trigger_sides[4][2] =
   {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
+    // center side       border side
+    { CH_SIDE_TOP,     CH_SIDE_BOTTOM  },      // check top
+    { CH_SIDE_LEFT,    CH_SIDE_RIGHT   },      // check left
+    { CH_SIDE_RIGHT,   CH_SIDE_LEFT    },      // check right
+    { CH_SIDE_BOTTOM,  CH_SIDE_TOP     }       // check bottom
   };
+  int i;
+
+  if (!IS_PLAYER(x, y))
+    return;
+
+  struct PlayerInfo *player = PLAYERINFO(x, y);
+
+  if (player->is_moving)
+    return;
+
+  for (i = 0; i < NUM_DIRECTIONS; i++)
+  {
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
+    int border_side = trigger_sides[i][1];
+    int border_element;
+
+    if (!IN_LEV_FIELD(xx, yy))
+      continue;
+
+    if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+      continue;                // center and border element not connected
+
+    border_element = Tile[xx][yy];
+
+    CheckElementChangeByPlayer(xx, yy, border_element, CE_NEXT_TO_PLAYER,
+                               player->index_bit, border_side);
+    CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+                                        CE_PLAYER_NEXT_TO_X,
+                                        player->index_bit, border_side);
+
+    /* use player element that is initially defined in the level playfield,
+       not the player element that corresponds to the runtime player number
+       (example: a level that contains EL_PLAYER_3 as the only player would
+       incorrectly give EL_PLAYER_1 for "player->element_nr") */
+
+    CheckElementChangeBySide(xx, yy, border_element, player->initial_element,
+                             CE_NEXT_TO_X, border_side);
+  }
+}
+
+void TestIfPlayerTouchesCustomElement(int x, int y)
+{
+  struct XY *xy = xy_topdown;
   static int trigger_sides[4][2] =
   {
     // center side       border side
@@ -13304,8 +13703,8 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int center_side = trigger_sides[i][0];
     int border_side = trigger_sides[i][1];
     int border_element;
@@ -13339,8 +13738,9 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
           incorrectly give EL_PLAYER_1 for "player->element_nr") */
        int player_element = PLAYERINFO(x, y)->initial_element;
 
+       // as element "X" is the player here, check opposite (center) side
        CheckElementChangeBySide(xx, yy, border_element, player_element,
-                                CE_TOUCHING_X, border_side);
+                                CE_TOUCHING_X, center_side);
       }
     }
     else if (IS_PLAYER(xx, yy))                // player found at border element
@@ -13366,8 +13766,9 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
           incorrectly give EL_PLAYER_1 for "player->element_nr") */
        int player_element = PLAYERINFO(xx, yy)->initial_element;
 
+       // as element "X" is the player here, check opposite (border) side
        CheckElementChangeBySide(x, y, center_element, player_element,
-                                CE_TOUCHING_X, center_side);
+                                CE_TOUCHING_X, border_side);
       }
 
       break;
@@ -13375,15 +13776,48 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
   }
 }
 
-void TestIfElementTouchesCustomElement(int x, int y)
+void TestIfElementNextToCustomElement(int x, int y)
 {
-  static int xy[4][2] =
+  struct XY *xy = xy_topdown;
+  static int trigger_sides[4][2] =
   {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
+    // center side     border side
+    { CH_SIDE_TOP,     CH_SIDE_BOTTOM  },      // check top
+    { CH_SIDE_LEFT,    CH_SIDE_RIGHT   },      // check left
+    { CH_SIDE_RIGHT,   CH_SIDE_LEFT    },      // check right
+    { CH_SIDE_BOTTOM,  CH_SIDE_TOP     }       // check bottom
   };
+  int center_element = Tile[x][y];     // should always be non-moving!
+  int i;
+
+  if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+    return;
+
+  for (i = 0; i < NUM_DIRECTIONS; i++)
+  {
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
+    int border_side = trigger_sides[i][1];
+    int border_element;
+
+    if (!IN_LEV_FIELD(xx, yy))
+      continue;
+
+    if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+      continue;                        // center and border element not connected
+
+    border_element = Tile[xx][yy];
+
+    // check for change of center element (but change it only once)
+    if (CheckElementChangeBySide(x, y, center_element, border_element,
+                                 CE_NEXT_TO_X, border_side))
+      break;
+  }
+}
+
+void TestIfElementTouchesCustomElement(int x, int y)
+{
+  struct XY *xy = xy_topdown;
   static int trigger_sides[4][2] =
   {
     // center side     border side
@@ -13406,8 +13840,8 @@ void TestIfElementTouchesCustomElement(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int border_element;
 
     border_element_old[i] = -1;
@@ -13429,8 +13863,8 @@ void TestIfElementTouchesCustomElement(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int center_side = trigger_sides[i][0];
     int border_element = border_element_old[i];
 
@@ -13441,13 +13875,13 @@ void TestIfElementTouchesCustomElement(int x, int y)
     CheckElementChangeBySide(xx, yy, border_element, center_element,
                             CE_TOUCHING_X, center_side);
 
-    // (center element cannot be player, so we dont have to check this here)
+    // (center element cannot be player, so we don't have to check this here)
   }
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int border_side = trigger_sides[i][1];
     int border_element = border_element_old[i];
 
@@ -13468,6 +13902,7 @@ void TestIfElementTouchesCustomElement(int x, int y)
         incorrectly give EL_PLAYER_1 for "player->element_nr") */
       int player_element = PLAYERINFO(xx, yy)->initial_element;
 
+      // as element "X" is the player here, check opposite (border) side
       CheckElementChangeBySide(x, y, center_element, player_element,
                               CE_TOUCHING_X, border_side);
     }
@@ -13534,13 +13969,7 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
   int i, kill_x = -1, kill_y = -1;
 
   int bad_element = -1;
-  static int test_xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *test_xy = xy_topdown;
   static int test_dir[4] =
   {
     MV_UP,
@@ -13553,8 +13982,8 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
   {
     int test_x, test_y, test_move_dir, test_element;
 
-    test_x = good_x + test_xy[i][0];
-    test_y = good_y + test_xy[i][1];
+    test_x = good_x + test_xy[i].x;
+    test_y = good_y + test_xy[i].y;
 
     if (!IN_LEV_FIELD(test_x, test_y))
       continue;
@@ -13599,13 +14028,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
 {
   int i, kill_x = -1, kill_y = -1;
   int bad_element = Tile[bad_x][bad_y];
-  static int test_xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *test_xy = xy_topdown;
   static int touch_dir[4] =
   {
     MV_LEFT | MV_RIGHT,
@@ -13628,8 +14051,8 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
   {
     int test_x, test_y, test_move_dir, test_element;
 
-    test_x = bad_x + test_xy[i][0];
-    test_y = bad_y + test_xy[i][1];
+    test_x = bad_x + test_xy[i].x;
+    test_y = bad_y + test_xy[i].y;
 
     if (!IN_LEV_FIELD(test_x, test_y))
       continue;
@@ -13781,20 +14204,14 @@ void TestIfBadThingTouchesFriend(int x, int y)
 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
 {
   int i, kill_x = bad_x, kill_y = bad_y;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int x, y, element;
 
-    x = bad_x + xy[i][0];
-    y = bad_y + xy[i][1];
+    x = bad_x + xy[i].x;
+    y = bad_y + xy[i].y;
     if (!IN_LEV_FIELD(x, y))
       continue;
 
@@ -13843,7 +14260,7 @@ void KillPlayer(struct PlayerInfo *player)
   player->killed = TRUE;
 
   // remove accessible field at the player's position
-  Tile[jx][jy] = EL_EMPTY;
+  RemoveField(jx, jy);
 
   // deactivate shield (else Bang()/Explode() would not work right)
   player->shield_normal_time_left = 0;
@@ -13889,7 +14306,6 @@ void BuryPlayer(struct PlayerInfo *player)
     return;
 
   PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING);
-  PlayLevelSound(jx, jy, SND_GAME_LOSING);
 
   RemovePlayer(player);
 
@@ -14057,7 +14473,6 @@ static int DigField(struct PlayerInfo *player,
       return MP_NO_ACTION;
     }
   }
-
   if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
     old_element = Back[jx][jy];
 
@@ -14069,7 +14484,7 @@ static int DigField(struct PlayerInfo *player,
   if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
     return MP_NO_ACTION;       // field has no opening in this direction
 
-  if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
+  if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element, opposite_direction))
     return MP_NO_ACTION;       // field has no opening in this direction
 
   if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
@@ -14307,9 +14722,13 @@ static int DigField(struct PlayerInfo *player,
     }
     else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
     {
-      player->shield_normal_time_left += level.shield_normal_time;
+      int shield_time = (element == EL_SHIELD_DEADLY ?
+                        level.shield_deadly_time :
+                        level.shield_normal_time);
+
+      player->shield_normal_time_left += shield_time;
       if (element == EL_SHIELD_DEADLY)
-       player->shield_deadly_time_left += level.shield_deadly_time;
+       player->shield_deadly_time_left += shield_time;
     }
     else if (element == EL_DYNAMITE ||
             element == EL_EM_DYNAMITE ||
@@ -14544,7 +14963,7 @@ static int DigField(struct PlayerInfo *player,
 
        LevelSolved();
 
-       PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
+       PlaySound(SND_GAME_SOKOBAN_SOLVING);
       }
     }
     else
@@ -14629,7 +15048,7 @@ static int DigField(struct PlayerInfo *player,
             element == EL_DC_SWITCHGATE_SWITCH_UP ||
             element == EL_DC_SWITCHGATE_SWITCH_DOWN)
     {
-      ToggleSwitchgateSwitch(x, y);
+      ToggleSwitchgateSwitch();
     }
     else if (element == EL_LIGHT_SWITCH ||
             element == EL_LIGHT_SWITCH_ACTIVE)
@@ -14670,7 +15089,7 @@ static int DigField(struct PlayerInfo *player,
       if (level.time > 0 || level.use_time_orb_bug)
       {
        TimeLeft += level.time_orb_time;
-       game.no_time_limit = FALSE;
+       game.no_level_time_limit = FALSE;
 
        game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
 
@@ -15037,15 +15456,15 @@ void InitPlayLevelSound(void)
   loop_sound_volume = checked_calloc(num_sounds * sizeof(int));
 }
 
-static void PlayLevelSound(int x, int y, int nr)
+static void PlayLevelSoundExt(int x, int y, int nr, boolean is_loop_sound)
 {
   int sx = SCREENX(x), sy = SCREENY(y);
   int volume, stereo_position;
   int max_distance = 8;
-  int type = (IS_LOOP_SOUND(nr) ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
+  int type = (is_loop_sound ? SND_CTRL_PLAY_LOOP : SND_CTRL_PLAY_SOUND);
 
-  if ((!setup.sound_simple && !IS_LOOP_SOUND(nr)) ||
-      (!setup.sound_loops && IS_LOOP_SOUND(nr)))
+  if ((!setup.sound_simple && !is_loop_sound) ||
+      (!setup.sound_loops && is_loop_sound))
     return;
 
   if (!IN_LEV_FIELD(x, y) ||
@@ -15067,7 +15486,7 @@ static void PlayLevelSound(int x, int y, int nr)
                     (sx + max_distance) * SOUND_MAX_LEFT2RIGHT /
                     (SCR_FIELDX + 2 * max_distance));
 
-  if (IS_LOOP_SOUND(nr))
+  if (is_loop_sound)
   {
     /* This assures that quieter loop sounds do not overwrite louder ones,
        while restarting sound volume comparison with each new game frame. */
@@ -15082,6 +15501,11 @@ static void PlayLevelSound(int x, int y, int nr)
   PlaySoundExt(nr, volume, stereo_position, type);
 }
 
+static void PlayLevelSound(int x, int y, int nr)
+{
+  PlayLevelSoundExt(x, y, nr, IS_LOOP_SOUND(nr));
+}
+
 static void PlayLevelSoundNearest(int x, int y, int sound_action)
 {
   PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) :
@@ -15131,10 +15555,12 @@ static void StopLevelSoundActionIfLoop(int x, int y, int action)
 
 static int getLevelMusicNr(void)
 {
+  int level_pos = level_nr - leveldir_current->first_level;
+
   if (levelset.music[level_nr] != MUS_UNDEFINED)
     return levelset.music[level_nr];           // from config file
   else
-    return MAP_NOCONF_MUSIC(level_nr);         // from music dir
+    return MAP_NOCONF_MUSIC(level_pos);                // from music dir
 }
 
 static void FadeLevelSounds(void)
@@ -15168,6 +15594,338 @@ static void PlayLevelMusic(void)
     PlayMusicLoop(music_nr);
 }
 
+static int getSoundAction_BD(int sample)
+{
+  switch (sample)
+  {
+    case GD_S_STONE_PUSHING:
+    case GD_S_MEGA_STONE_PUSHING:
+    case GD_S_FLYING_STONE_PUSHING:
+    case GD_S_WAITING_STONE_PUSHING:
+    case GD_S_CHASING_STONE_PUSHING:
+    case GD_S_NUT_PUSHING:
+    case GD_S_NITRO_PACK_PUSHING:
+    case GD_S_BLADDER_PUSHING:
+    case GD_S_BOX_PUSHING:
+      return ACTION_PUSHING;
+
+    case GD_S_STONE_FALLING:
+    case GD_S_MEGA_STONE_FALLING:
+    case GD_S_FLYING_STONE_FALLING:
+    case GD_S_NUT_FALLING:
+    case GD_S_DIRT_BALL_FALLING:
+    case GD_S_DIRT_LOOSE_FALLING:
+    case GD_S_NITRO_PACK_FALLING:
+    case GD_S_FALLING_WALL_FALLING:
+      return ACTION_FALLING;
+
+    case GD_S_STONE_IMPACT:
+    case GD_S_MEGA_STONE_IMPACT:
+    case GD_S_FLYING_STONE_IMPACT:
+    case GD_S_NUT_IMPACT:
+    case GD_S_DIRT_BALL_IMPACT:
+    case GD_S_DIRT_LOOSE_IMPACT:
+    case GD_S_NITRO_PACK_IMPACT:
+    case GD_S_FALLING_WALL_IMPACT:
+      return ACTION_IMPACT;
+
+    case GD_S_NUT_CRACKING:
+      return ACTION_BREAKING;
+
+    case GD_S_EXPANDING_WALL:
+    case GD_S_WALL_REAPPEARING:
+    case GD_S_SLIME:
+    case GD_S_LAVA:
+    case GD_S_ACID_SPREADING:
+      return ACTION_GROWING;
+
+    case GD_S_DIAMOND_COLLECTING:
+    case GD_S_FLYING_DIAMOND_COLLECTING:
+    case GD_S_SKELETON_COLLECTING:
+    case GD_S_PNEUMATIC_COLLECTING:
+    case GD_S_BOMB_COLLECTING:
+    case GD_S_CLOCK_COLLECTING:
+    case GD_S_SWEET_COLLECTING:
+    case GD_S_KEY_COLLECTING:
+    case GD_S_DIAMOND_KEY_COLLECTING:
+      return ACTION_COLLECTING;
+
+    case GD_S_BOMB_PLACING:
+    case GD_S_REPLICATOR:
+      return ACTION_DROPPING;
+
+    case GD_S_BLADDER_MOVING:
+      return ACTION_MOVING;
+
+    case GD_S_BLADDER_SPENDER:
+    case GD_S_BLADDER_CONVERTING:
+    case GD_S_GRAVITY_CHANGING:
+      return ACTION_CHANGING;
+
+    case GD_S_BITER_EATING:
+      return ACTION_EATING;
+
+    case GD_S_DOOR_OPENING:
+    case GD_S_CRACKING:
+      return ACTION_OPENING;
+
+    case GD_S_DIRT_WALKING:
+      return ACTION_DIGGING;
+
+    case GD_S_EMPTY_WALKING:
+      return ACTION_WALKING;
+
+    case GD_S_SWITCH_BITER:
+    case GD_S_SWITCH_CREATURES:
+    case GD_S_SWITCH_GRAVITY:
+    case GD_S_SWITCH_EXPANDING:
+    case GD_S_SWITCH_CONVEYOR:
+    case GD_S_SWITCH_REPLICATOR:
+    case GD_S_STIRRING:
+      return ACTION_ACTIVATING;
+
+    case GD_S_TELEPORTER:
+      return ACTION_PASSING;
+
+    case GD_S_EXPLODING:
+    case GD_S_BOMB_EXPLODING:
+    case GD_S_GHOST_EXPLODING:
+    case GD_S_VOODOO_EXPLODING:
+    case GD_S_NITRO_PACK_EXPLODING:
+      return ACTION_EXPLODING;
+
+    case GD_S_COVERING:
+    case GD_S_AMOEBA:
+    case GD_S_MAGIC_WALL:
+    case GD_S_PNEUMATIC_HAMMER:
+    case GD_S_WATER:
+      return ACTION_ACTIVE;
+
+    case GD_S_DIAMOND_FALLING_RANDOM:
+    case GD_S_DIAMOND_FALLING_1:
+    case GD_S_DIAMOND_FALLING_2:
+    case GD_S_DIAMOND_FALLING_3:
+    case GD_S_DIAMOND_FALLING_4:
+    case GD_S_DIAMOND_FALLING_5:
+    case GD_S_DIAMOND_FALLING_6:
+    case GD_S_DIAMOND_FALLING_7:
+    case GD_S_DIAMOND_FALLING_8:
+    case GD_S_DIAMOND_IMPACT_RANDOM:
+    case GD_S_DIAMOND_IMPACT_1:
+    case GD_S_DIAMOND_IMPACT_2:
+    case GD_S_DIAMOND_IMPACT_3:
+    case GD_S_DIAMOND_IMPACT_4:
+    case GD_S_DIAMOND_IMPACT_5:
+    case GD_S_DIAMOND_IMPACT_6:
+    case GD_S_DIAMOND_IMPACT_7:
+    case GD_S_DIAMOND_IMPACT_8:
+    case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+    case GD_S_FLYING_DIAMOND_FALLING_1:
+    case GD_S_FLYING_DIAMOND_FALLING_2:
+    case GD_S_FLYING_DIAMOND_FALLING_3:
+    case GD_S_FLYING_DIAMOND_FALLING_4:
+    case GD_S_FLYING_DIAMOND_FALLING_5:
+    case GD_S_FLYING_DIAMOND_FALLING_6:
+    case GD_S_FLYING_DIAMOND_FALLING_7:
+    case GD_S_FLYING_DIAMOND_FALLING_8:
+    case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+    case GD_S_FLYING_DIAMOND_IMPACT_1:
+    case GD_S_FLYING_DIAMOND_IMPACT_2:
+    case GD_S_FLYING_DIAMOND_IMPACT_3:
+    case GD_S_FLYING_DIAMOND_IMPACT_4:
+    case GD_S_FLYING_DIAMOND_IMPACT_5:
+    case GD_S_FLYING_DIAMOND_IMPACT_6:
+    case GD_S_FLYING_DIAMOND_IMPACT_7:
+    case GD_S_FLYING_DIAMOND_IMPACT_8:
+    case GD_S_TIMEOUT_0:
+    case GD_S_TIMEOUT_1:
+    case GD_S_TIMEOUT_2:
+    case GD_S_TIMEOUT_3:
+    case GD_S_TIMEOUT_4:
+    case GD_S_TIMEOUT_5:
+    case GD_S_TIMEOUT_6:
+    case GD_S_TIMEOUT_7:
+    case GD_S_TIMEOUT_8:
+    case GD_S_TIMEOUT_9:
+    case GD_S_TIMEOUT_10:
+    case GD_S_BONUS_LIFE:
+      // trigger special post-processing (and force sound to be non-looping)
+      return ACTION_OTHER;
+
+    case GD_S_AMOEBA_MAGIC:
+    case GD_S_FINISHED:
+      // trigger special post-processing (and force sound to be looping)
+      return ACTION_DEFAULT;
+
+    default:
+      return ACTION_DEFAULT;
+  }
+}
+
+static int getSoundEffect_BD(int element_bd, int sample)
+{
+  int sound_action = getSoundAction_BD(sample);
+  int sound_effect = element_info[SND_ELEMENT(element_bd)].sound[sound_action];
+  int nr;
+
+  // standard sounds
+  if (sound_action != ACTION_OTHER &&
+      sound_action != ACTION_DEFAULT)
+    return sound_effect;
+
+  // special post-processing for some sounds
+  switch (sample)
+  {
+    case GD_S_DIAMOND_FALLING_RANDOM:
+    case GD_S_DIAMOND_FALLING_1:
+    case GD_S_DIAMOND_FALLING_2:
+    case GD_S_DIAMOND_FALLING_3:
+    case GD_S_DIAMOND_FALLING_4:
+    case GD_S_DIAMOND_FALLING_5:
+    case GD_S_DIAMOND_FALLING_6:
+    case GD_S_DIAMOND_FALLING_7:
+    case GD_S_DIAMOND_FALLING_8:
+      nr = (sample == GD_S_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_DIAMOND_FALLING_1);
+      sound_effect = SND_BDX_DIAMOND_FALLING_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BDX_DIAMOND_FALLING;
+      break;
+
+    case GD_S_DIAMOND_IMPACT_RANDOM:
+    case GD_S_DIAMOND_IMPACT_1:
+    case GD_S_DIAMOND_IMPACT_2:
+    case GD_S_DIAMOND_IMPACT_3:
+    case GD_S_DIAMOND_IMPACT_4:
+    case GD_S_DIAMOND_IMPACT_5:
+    case GD_S_DIAMOND_IMPACT_6:
+    case GD_S_DIAMOND_IMPACT_7:
+    case GD_S_DIAMOND_IMPACT_8:
+      nr = (sample == GD_S_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_DIAMOND_IMPACT_1);
+      sound_effect = SND_BDX_DIAMOND_IMPACT_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BDX_DIAMOND_IMPACT;
+      break;
+
+    case GD_S_FLYING_DIAMOND_FALLING_RANDOM:
+    case GD_S_FLYING_DIAMOND_FALLING_1:
+    case GD_S_FLYING_DIAMOND_FALLING_2:
+    case GD_S_FLYING_DIAMOND_FALLING_3:
+    case GD_S_FLYING_DIAMOND_FALLING_4:
+    case GD_S_FLYING_DIAMOND_FALLING_5:
+    case GD_S_FLYING_DIAMOND_FALLING_6:
+    case GD_S_FLYING_DIAMOND_FALLING_7:
+    case GD_S_FLYING_DIAMOND_FALLING_8:
+      nr = (sample == GD_S_FLYING_DIAMOND_FALLING_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_FLYING_DIAMOND_FALLING_1);
+      sound_effect = SND_BDX_FLYING_DIAMOND_FALLING_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BDX_FLYING_DIAMOND_FALLING;
+      break;
+
+    case GD_S_FLYING_DIAMOND_IMPACT_RANDOM:
+    case GD_S_FLYING_DIAMOND_IMPACT_1:
+    case GD_S_FLYING_DIAMOND_IMPACT_2:
+    case GD_S_FLYING_DIAMOND_IMPACT_3:
+    case GD_S_FLYING_DIAMOND_IMPACT_4:
+    case GD_S_FLYING_DIAMOND_IMPACT_5:
+    case GD_S_FLYING_DIAMOND_IMPACT_6:
+    case GD_S_FLYING_DIAMOND_IMPACT_7:
+    case GD_S_FLYING_DIAMOND_IMPACT_8:
+      nr = (sample == GD_S_FLYING_DIAMOND_IMPACT_RANDOM ? GetSimpleRandom(8) :
+           sample - GD_S_FLYING_DIAMOND_IMPACT_1);
+      sound_effect = SND_BDX_FLYING_DIAMOND_IMPACT_RANDOM_1 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL)
+       sound_effect = SND_BDX_FLYING_DIAMOND_IMPACT;
+      break;
+
+    case GD_S_TIMEOUT_0:
+    case GD_S_TIMEOUT_1:
+    case GD_S_TIMEOUT_2:
+    case GD_S_TIMEOUT_3:
+    case GD_S_TIMEOUT_4:
+    case GD_S_TIMEOUT_5:
+    case GD_S_TIMEOUT_6:
+    case GD_S_TIMEOUT_7:
+    case GD_S_TIMEOUT_8:
+    case GD_S_TIMEOUT_9:
+    case GD_S_TIMEOUT_10:
+      nr = sample - GD_S_TIMEOUT_0;
+      sound_effect = SND_GAME_RUNNING_OUT_OF_TIME_0 + nr;
+
+      if (getSoundInfoEntryFilename(sound_effect) == NULL && sample != GD_S_TIMEOUT_0)
+       sound_effect = SND_GAME_RUNNING_OUT_OF_TIME;
+      break;
+
+    case GD_S_BONUS_LIFE:
+      sound_effect = SND_GAME_HEALTH_BONUS;
+      break;
+
+    case GD_S_AMOEBA_MAGIC:
+      sound_effect = SND_BDX_AMOEBA_1_OTHER;
+      break;
+
+    case GD_S_FINISHED:
+      sound_effect = SND_GAME_LEVELTIME_BONUS;
+      break;
+
+    default:
+      sound_effect = SND_UNDEFINED;
+      break;
+  }
+
+  return sound_effect;
+}
+
+void PlayLevelSound_BD(int xx, int yy, int element_bd, int sample)
+{
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
+  int sound_effect = getSoundEffect_BD(element, sample);
+  int sound_action = getSoundAction_BD(sample);
+  boolean is_loop_sound = IS_LOOP_SOUND(sound_effect);
+  int offset = 0;
+  int x = xx - offset;
+  int y = yy - offset;
+
+  // some sound actions are always looping in native BD game engine
+  if (sound_action == ACTION_DEFAULT)
+    is_loop_sound = TRUE;
+
+  // some sound actions are always non-looping in native BD game engine
+  if (sound_action == ACTION_FALLING ||
+      sound_action == ACTION_MOVING ||
+      sound_action == ACTION_OTHER)
+    is_loop_sound = FALSE;
+
+  if (sound_effect != SND_UNDEFINED)
+    PlayLevelSoundExt(x, y, sound_effect, is_loop_sound);
+}
+
+void StopSound_BD(int element_bd, int sample)
+{
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
+  int sound_effect = getSoundEffect_BD(element, sample);
+
+  if (sound_effect != SND_UNDEFINED)
+    StopSound(sound_effect);
+}
+
+boolean isSoundPlaying_BD(int element_bd, int sample)
+{
+  int element = (element_bd > -1 ? map_element_BD_to_RND_game(element_bd) : 0);
+  int sound_effect = getSoundEffect_BD(element, sample);
+
+  if (sound_effect != SND_UNDEFINED)
+    return isSoundPlaying(sound_effect);
+
+  return FALSE;
+}
+
 void PlayLevelSound_EM(int xx, int yy, int element_em, int sample)
 {
   int element = (element_em > -1 ? map_element_EM_to_RND_game(element_em) : 0);
@@ -15480,15 +16238,22 @@ void RequestQuitGameExt(boolean skip_request, boolean quick_quit, char *message)
     {
       // prevent short reactivation of overlay buttons while closing door
       SetOverlayActive(FALSE);
+      UnmapGameButtons();
 
       // door may still be open due to skipped or envelope style request
-      CloseDoor(DOOR_CLOSE_1);
+      CloseDoor(score_info_tape_play ? DOOR_CLOSE_ALL : DOOR_CLOSE_1);
     }
 
     if (network.enabled)
+    {
       SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER);
+    }
     else
     {
+      // when using BD game engine, cover screen before fading out
+      if (!quick_quit && level.game_engine_type == GAME_ENGINE_TYPE_BD)
+       game_bd.cover_screen = TRUE;
+
       if (quick_quit)
        FadeSkipNextFadeIn();
 
@@ -15515,27 +16280,59 @@ void RequestQuitGame(boolean escape_key_pressed)
   boolean quick_quit = ((escape_key_pressed && !ask_on_escape) ||
                        level_editor_test_game);
   boolean skip_request = (game.all_players_gone || !setup.ask_on_quit_game ||
-                         quick_quit);
+                         quick_quit || score_info_tape_play);
 
   RequestQuitGameExt(skip_request, quick_quit,
                     "Do you really want to quit the game?");
 }
 
-void RequestRestartGame(char *message)
+static char *getRestartGameMessage(void)
 {
-  game.restart_game_message = NULL;
+  boolean play_again = hasStartedNetworkGame();
+  static char message[MAX_OUTPUT_LINESIZE];
+  char *game_over_text = "Game over!";
+  char *play_again_text = " Play it again?";
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
+      game_mm.game_over_message != NULL)
+    game_over_text = game_mm.game_over_message;
+
+  snprintf(message, MAX_OUTPUT_LINESIZE, "%s%s", game_over_text,
+          (play_again ? play_again_text : ""));
 
+  return message;
+}
+
+static void RequestRestartGame(void)
+{
+  char *message = getRestartGameMessage();
   boolean has_started_game = hasStartedNetworkGame();
   int request_mode = (has_started_game ? REQ_ASK : REQ_CONFIRM);
+  int door_state = DOOR_CLOSE_1;
 
-  if (Request(message, request_mode | REQ_STAY_CLOSED) && has_started_game)
+  boolean restart_wanted = (Request(message, request_mode | REQ_STAY_OPEN) && has_started_game);
+
+  // if no restart wanted, continue with next level for BD style intermission levels
+  if (!restart_wanted && !level_editor_test_game && level.bd_intermission)
+  {
+    boolean success = AdvanceToNextLevel();
+
+    restart_wanted = (success && setup.auto_play_next_level);
+  }
+
+  if (restart_wanted)
   {
+    CloseDoor(door_state);
+
     StartGameActions(network.enabled, setup.autorecord, level.random_seed);
   }
   else
   {
-    // needed in case of envelope request to close game panel
-    CloseDoor(DOOR_CLOSE_1);
+    // if game was invoked from level editor, also close tape recorder door
+    if (level_editor_test_game)
+      door_state = DOOR_CLOSE_ALL;
+
+    CloseDoor(door_state);
 
     SetGameStatus(GAME_MODE_MAIN);
 
@@ -15543,42 +16340,72 @@ void RequestRestartGame(char *message)
   }
 }
 
-void CheckGameOver(void)
+boolean CheckRestartGame(void)
 {
-  static boolean last_game_over = FALSE;
   static int game_over_delay = 0;
   int game_over_delay_value = 50;
   boolean game_over = checkGameFailed();
 
-  // do not handle game over if request dialog is already active
-  if (game.request_active)
-    return;
-
-  // do not ask to play again if game was never actually played
-  if (!game.GamePlayed)
-    return;
-
   if (!game_over)
   {
-    last_game_over = FALSE;
     game_over_delay = game_over_delay_value;
 
-    return;
+    return FALSE;
   }
 
   if (game_over_delay > 0)
   {
+    if (game_over_delay == game_over_delay_value / 2)
+      PlaySound(SND_GAME_LOSING);
+
     game_over_delay--;
 
-    return;
+    return FALSE;
   }
 
-  if (last_game_over != game_over)
-    game.restart_game_message = (hasStartedNetworkGame() ?
-                                "Game over! Play it again?" :
-                                "Game over!");
+  // do not ask to play again if request dialog is already active
+  if (checkRequestActive())
+    return FALSE;
+
+  // do not ask to play again if request dialog already handled
+  if (game.RestartGameRequested)
+    return FALSE;
+
+  // do not ask to play again if game was never actually played
+  if (!game.GamePlayed)
+    return FALSE;
+
+  // do not ask to play again if this was disabled in setup menu
+  if (!setup.ask_on_game_over)
+    return FALSE;
+
+  game.RestartGameRequested = TRUE;
+
+  RequestRestartGame();
+
+  return TRUE;
+}
+
+boolean checkGameRunning(void)
+{
+  if (game_status != GAME_MODE_PLAYING)
+    return FALSE;
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD && !checkGameRunning_BD())
+    return FALSE;
+
+  return TRUE;
+}
+
+boolean checkGamePlaying(void)
+{
+  if (game_status != GAME_MODE_PLAYING)
+    return FALSE;
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD && !checkGamePlaying_BD())
+    return FALSE;
 
-  last_game_over = game_over;
+  return TRUE;
 }
 
 boolean checkGameSolved(void)
@@ -15589,7 +16416,9 @@ boolean checkGameSolved(void)
 
 boolean checkGameFailed(void)
 {
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    return (game_bd.game_over && !game_bd.level_solved);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     return (game_em.game_over && !game_em.level_solved);
   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
     return (game_sp.game_over && !game_sp.level_solved);
@@ -15604,6 +16433,11 @@ boolean checkGameEnded(void)
   return (checkGameSolved() || checkGameFailed());
 }
 
+boolean checkRequestActive(void)
+{
+  return (game.request_active || game.envelope_active || game.any_door_active);
+}
+
 
 // ----------------------------------------------------------------------------
 // random generator functions
@@ -15762,7 +16596,7 @@ static ListNode *SaveEngineSnapshotBuffers(void)
   if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
     SaveEngineSnapshotValues_SP(&buffers);
   if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
-    SaveEngineSnapshotValues_MM(&buffers);
+    SaveEngineSnapshotValues_MM();
 
   // save values stored in special snapshot structure
 
@@ -15785,6 +16619,7 @@ static ListNode *SaveEngineSnapshotBuffers(void)
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeFrames));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimePlayed));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TimeLeft));
+  SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTimeFrames));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(TapeTime));
 
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(ScreenMovDir));
@@ -15827,6 +16662,7 @@ static ListNode *SaveEngineSnapshotBuffers(void)
 
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom));
+  SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandomStatic));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction));
   SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir));
@@ -15999,6 +16835,11 @@ static struct
     GAME_CTRL_ID_LOAD,                         NULL,
     TRUE, FALSE,                               "load game"
   },
+  {
+    IMG_GFX_GAME_BUTTON_RESTART,               &game.button.restart,
+    GAME_CTRL_ID_RESTART,                      NULL,
+    TRUE, FALSE,                               "restart game"
+  },
   {
     IMG_GFX_GAME_BUTTON_PANEL_STOP,            &game.button.panel_stop,
     GAME_CTRL_ID_PANEL_STOP,                   NULL,
@@ -16014,6 +16855,11 @@ static struct
     GAME_CTRL_ID_PANEL_PLAY,                   NULL,
     FALSE, FALSE,                              "play game"
   },
+  {
+    IMG_GFX_GAME_BUTTON_PANEL_RESTART,         &game.button.panel_restart,
+    GAME_CTRL_ID_PANEL_RESTART,                        NULL,
+    FALSE, FALSE,                              "restart game"
+  },
   {
     IMG_GFX_GAME_BUTTON_TOUCH_STOP,            &game.button.touch_stop,
     GAME_CTRL_ID_TOUCH_STOP,                   NULL,
@@ -16024,6 +16870,11 @@ static struct
     GAME_CTRL_ID_TOUCH_PAUSE,                  NULL,
     FALSE, TRUE,                               "pause game"
   },
+  {
+    IMG_GFX_GAME_BUTTON_TOUCH_RESTART,         &game.button.touch_restart,
+    GAME_CTRL_ID_TOUCH_RESTART,                        NULL,
+    FALSE, TRUE,                               "restart game"
+  },
   {
     IMG_GFX_GAME_BUTTON_SOUND_MUSIC,           &game.button.sound_music,
     SOUND_CTRL_ID_MUSIC,                       &setup.sound_music,
@@ -16086,6 +16937,10 @@ void CreateGameButtons(void)
     int y = (is_touch_button ? pos->y : GDI_ACTIVE_POS(pos->y));
     int id = i;
 
+    // do not use touch buttons if overlay touch buttons are disabled
+    if (is_touch_button && !setup.touch.overlay_buttons)
+      continue;
+
     if (gfx->bitmap == NULL)
     {
       game_gadget[id] = NULL;
@@ -16099,7 +16954,10 @@ void CreateGameButtons(void)
        id == GAME_CTRL_ID_PLAY ||
        id == GAME_CTRL_ID_PANEL_PLAY ||
        id == GAME_CTRL_ID_SAVE ||
-       id == GAME_CTRL_ID_LOAD)
+       id == GAME_CTRL_ID_LOAD ||
+       id == GAME_CTRL_ID_RESTART ||
+       id == GAME_CTRL_ID_PANEL_RESTART ||
+       id == GAME_CTRL_ID_TOUCH_RESTART)
     {
       button_type = GD_TYPE_NORMAL_BUTTON;
       checked = FALSE;
@@ -16222,6 +17080,10 @@ void ModifyPauseButtons(void)
   };
   int i;
 
+  // do not redraw pause button on closed door (may happen when restarting game)
+  if (!(GetDoorState() & DOOR_OPEN_1))
+    return;
+
   for (i = 0; ids[i] > -1; i++)
     ModifyGadget(game_gadget[ids[i]], GDI_CHECKED, tape.pausing, GDI_END);
 }
@@ -16231,8 +17093,15 @@ static void MapGameButtonsExt(boolean on_tape)
   int i;
 
   for (i = 0; i < NUM_GAME_BUTTONS; i++)
+  {
+    if ((i == GAME_CTRL_ID_UNDO ||
+        i == GAME_CTRL_ID_REDO) &&
+       game_status != GAME_MODE_PLAYING)
+      continue;
+
     if (!on_tape || gamebutton_info[i].allowed_on_tape)
       MapGadget(game_gadget[i]);
+  }
 
   UnmapGameButtonsAtSamePosition_All();
 
@@ -16372,13 +17241,7 @@ static void HandleGameButtonsExt(int id, int button)
     case GAME_CTRL_ID_STOP:
     case GAME_CTRL_ID_PANEL_STOP:
     case GAME_CTRL_ID_TOUCH_STOP:
-      if (game_status == GAME_MODE_MAIN)
-       break;
-
-      if (tape.playing)
-       TapeStop();
-      else
-       RequestQuitGame(FALSE);
+      TapeStopGame();
 
       break;
 
@@ -16442,6 +17305,13 @@ static void HandleGameButtonsExt(int id, int button)
       TapeQuickLoad();
       break;
 
+    case GAME_CTRL_ID_RESTART:
+    case GAME_CTRL_ID_PANEL_RESTART:
+    case GAME_CTRL_ID_TOUCH_RESTART:
+      TapeRestartGame();
+
+      break;
+
     case SOUND_CTRL_ID_MUSIC:
     case SOUND_CTRL_ID_PANEL_MUSIC:
       if (setup.sound_music)
index 89ec940c23a33818c77b5ae80771645f409d4435..c5eba4f155939e7296315d0bee1acc780b9b6287 100644 (file)
@@ -52,6 +52,9 @@ struct GamePanelInfo
 {
   struct TextPosInfo level_number;
   struct TextPosInfo gems;
+  struct TextPosInfo gems_needed;
+  struct TextPosInfo gems_collected;
+  struct TextPosInfo gems_score;
   struct TextPosInfo inventory_count;
   struct TextPosInfo inventory_first[NUM_PANEL_INVENTORY];
   struct TextPosInfo inventory_last[NUM_PANEL_INVENTORY];
@@ -123,6 +126,8 @@ struct GameButtonInfo
   struct XY pause2;
   struct XY load;
 
+  struct XY restart;
+
   struct XY sound_music;
   struct XY sound_loops;
   struct XY sound_simple;
@@ -131,12 +136,15 @@ struct GameButtonInfo
   struct XY panel_pause;
   struct XY panel_play;
 
+  struct XY panel_restart;
+
   struct XY panel_sound_music;
   struct XY panel_sound_loops;
   struct XY panel_sound_simple;
 
   struct XY touch_stop;
   struct XY touch_pause;
+  struct XY touch_restart;
 };
 
 struct GameSnapshotInfo
@@ -158,14 +166,21 @@ struct GameInfo
 
   // values for graphics engine customization
   int graphics_engine_version;
+  boolean use_native_bd_graphics_engine;
   boolean use_native_emc_graphics_engine;
   boolean use_native_sp_graphics_engine;
   boolean use_masked_pushing;
   boolean use_masked_elements;
+  boolean use_masked_elements_initial;
+  int forced_scroll_x;
+  int forced_scroll_y;
   int forced_scroll_delay_value;
   int scroll_delay_value;
   int tile_size;
 
+  // values for sound engine customization
+  boolean use_native_bd_sound_engine;
+
   // constant within running game
   int engine_version;
   int emulation;
@@ -201,8 +216,8 @@ struct GameInfo
   int wind_direction;
 
   boolean explosions_delayed;
-  boolean envelope_active;
-  boolean no_time_limit;       // (variable only in very special case)
+  boolean no_level_time_limit; // (variable only in very special case)
+  boolean time_limit;          // forced by levelset config or setup option
 
   int time_final;              // time (in seconds) or steps left or played
   int score_time_final;                // time (in frames) or steps played
@@ -240,12 +255,10 @@ struct GameInfo
   // values for special game initialization control
   boolean restart_level;
 
-  // trigger message to ask for restarting the game
-  char *restart_game_message;
-
   // values for special request dialog control
   boolean request_active;
-  boolean request_active_or_moving;
+  boolean envelope_active;
+  boolean any_door_active;
 
   // values for special game control
   int centered_player_nr;
@@ -275,6 +288,8 @@ struct GameInfo
   int LevelSolved_CountingTime;
   int LevelSolved_CountingScore;
   int LevelSolved_CountingHealth;
+
+  boolean RestartGameRequested;
 };
 
 struct PlayerInfo
@@ -377,7 +392,7 @@ struct PlayerInfo
   int push_delay;
   int push_delay_value;
 
-  unsigned int actual_frame_counter;
+  DelayCounter actual_frame_counter;
 
   int drop_delay;
   int drop_pressed_delay;
@@ -425,13 +440,16 @@ void GameEnd(void);
 void MergeServerScore(void);
 
 void InitPlayerGfxAnimation(struct PlayerInfo *, int, int);
+
 void Moving2Blocked(int, int, int *, int *);
 void Blocked2Moving(int, int, int *, int *);
+
 void DrawDynamite(int, int);
 
 void StartGameActions(boolean, boolean, int);
 
 void GameActions(void);
+void GameActions_BD_Main(void);
 void GameActions_EM_Main(void);
 void GameActions_SP_Main(void);
 void GameActions_MM_Main(void);
@@ -453,12 +471,14 @@ void RaiseScoreElement(int);
 
 void RequestQuitGameExt(boolean, boolean, char *);
 void RequestQuitGame(boolean);
-void RequestRestartGame(char *);
-void CheckGameOver(void);
 
+boolean CheckRestartGame(void);
+boolean checkGameRunning(void);
+boolean checkGamePlaying(void);
 boolean checkGameSolved(void);
 boolean checkGameFailed(void);
 boolean checkGameEnded(void);
+boolean checkRequestActive(void);
 
 unsigned int InitEngineRandom_RND(int);
 unsigned int RND(int);
diff --git a/src/game_bd/COPYING b/src/game_bd/COPYING
new file mode 100644 (file)
index 0000000..bf2a883
--- /dev/null
@@ -0,0 +1,13 @@
+Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/src/game_bd/Makefile b/src/game_bd/Makefile
new file mode 100644 (file)
index 0000000..aa212f9
--- /dev/null
@@ -0,0 +1,80 @@
+# =============================================================================
+# Rocks'n'Diamonds - McDuffin Strikes Back!
+# -----------------------------------------------------------------------------
+# (c) 1995-2024 by Artsoft Entertainment
+#                  Holger Schemel
+#                  info@artsoft.org
+#                  https://www.artsoft.org/
+# -----------------------------------------------------------------------------
+# The native Boulder Dash game engine is based on:
+# - GDash by Czirkos Zoltan (2010)
+# -----------------------------------------------------------------------------
+# src/game_bd/Makefile
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# configuration
+# -----------------------------------------------------------------------------
+
+SRCS = main_bd.c       \
+       bd_cave.c       \
+       bd_cavedb.c     \
+       bd_caveengine.c \
+       bd_caveobject.c \
+       bd_bdcff.c      \
+       bd_caveset.c    \
+       bd_c64import.c  \
+       bd_gameplay.c   \
+       bd_graphics.c   \
+       bd_colors.c     \
+       bd_random.c     \
+       bd_sound.c
+
+OBJS = main_bd.o       \
+       bd_cave.o       \
+       bd_cavedb.o     \
+       bd_caveengine.o \
+       bd_caveobject.o \
+       bd_bdcff.o      \
+       bd_caveset.o    \
+       bd_c64import.o  \
+       bd_gameplay.o   \
+       bd_graphics.o   \
+       bd_colors.o     \
+       bd_random.o     \
+       bd_sound.o
+
+GAME_BD = game_bd.a
+
+
+# -----------------------------------------------------------------------------
+# build targets
+# -----------------------------------------------------------------------------
+
+all: $(GAME_BD)
+
+$(GAME_BD): $(OBJS)
+       $(AR) cr $(GAME_BD) $(OBJS)
+       $(RANLIB) $(GAME_BD)
+
+.c.o:
+       $(CC) $(PROFILING) $(CFLAGS) -c $*.c
+
+clean:
+       $(RM) $(OBJS)
+       $(RM) $(GAME_BD)
+
+
+# -----------------------------------------------------------------------------
+# development only
+# -----------------------------------------------------------------------------
+
+depend:
+       for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
+
+depend-clean:
+       $(RM) .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/src/game_bd/bd_bdcff.c b/src/game_bd/bd_bdcff.c
new file mode 100644 (file)
index 0000000..6a0a045
--- /dev/null
@@ -0,0 +1,1785 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+
+#include "main_bd.h"
+
+
+#define BDCFF_VERSION "0.5"
+
+// these are used for bdcff loading, storing the sizes of caves
+static int cavesize[6], intermissionsize[6];
+
+static boolean replay_store_from_bdcff(GdReplay *replay, const char *str)
+{
+  GdDirection dir;
+  boolean up, down, left, right;
+  boolean fire, suicide;
+  const char *num = NULL;
+  int count, i;
+
+  fire = suicide = up = down = left = right = FALSE;
+
+  for (i = 0; str[i] != 0; i++)
+  {
+    switch (str[i])
+    {
+      case 'U':
+       fire = TRUE;
+      case 'u':
+       up = TRUE;
+       break;
+
+      case 'D':
+       fire = TRUE;
+      case 'd':
+       down = TRUE;
+       break;
+
+      case 'L':
+       fire = TRUE;
+      case 'l':
+       left = TRUE;
+       break;
+
+      case 'R':
+       fire = TRUE;
+      case 'r':
+       right = TRUE;
+       break;
+
+      case 'F':
+       fire = TRUE;
+       break;
+      case 'k':
+       suicide = TRUE;
+       break;
+
+      case '.':
+       // do nothing, as all other movements are false
+       break;
+
+      case 'c':
+      case 'C':
+       // bdcff 'combined' flags. do nothing.
+       break;
+
+      default:
+       if (str[i] >= '0' && str[i] <= '9')
+       {
+         if (!num)
+           num = str + i;
+       }
+    }
+  }
+
+  dir = gd_direction_from_keypress(up, down, left, right);
+  count = 1;
+
+  if (num)
+    sscanf(num, "%d", &count);
+
+  for (i = 0; i < count; i++)
+    gd_replay_store_movement(replay, dir, fire, suicide);
+
+  return TRUE;
+}
+
+static boolean attrib_is_valid_for_cave(const char *attrib)
+{
+  int i;
+
+  // bdcff engine flag............
+  if (strcasecmp(attrib, "Engine") == 0)
+    return TRUE;
+
+  // old flags - for compatibility
+  if (strcasecmp(attrib, "BD1Scheduling") == 0)
+    return TRUE;
+
+  if (strcasecmp(attrib, "SnapExplosions") == 0)
+    return TRUE;
+
+  if (strcasecmp(attrib, "AmoebaProperties") == 0)
+    return TRUE;
+
+  // search in property database
+  for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
+    if (strcasecmp(gd_cave_properties[i].identifier, attrib) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+static boolean attrib_is_valid_for_caveset(const char *attrib)
+{
+  int i;
+
+  // search in property database
+  for (i = 0; gd_caveset_properties[i].identifier != NULL; i++)
+    if (strcasecmp(gd_caveset_properties[i].identifier, attrib) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+static boolean struct_set_property(void *str, const GdStructDescriptor *prop_desc,
+                                  const char *attrib, const char *param, int ratio)
+{
+  char **params;
+  int paramcount;
+  boolean identifier_found;
+  int paramindex = 0;
+  int i;
+  boolean was_string;
+
+  params = getSplitStringArray(param, " ", -1);
+  paramcount = getStringArrayLength(params);
+  identifier_found = FALSE;
+
+  // check all known tags. do not exit this loop if identifier_found == true...
+  // as there are more lines in the array which have the same identifier.
+  was_string = FALSE;
+
+  for (i = 0; prop_desc[i].identifier != NULL; i++)
+  {
+    if (strcasecmp(prop_desc[i].identifier, attrib) == 0)
+    {
+      // found the identifier
+      void *value = STRUCT_MEMBER_P(str, prop_desc[i].offset);
+
+      // these point to the same, but to avoid the awkward cast syntax
+      int *ivalue = value;
+      GdElement *evalue = value;
+      GdDirection *dvalue = value;
+      GdScheduling *svalue = value;
+      boolean *bvalue = value;
+      int j, k;
+
+      identifier_found = TRUE;
+
+      if (prop_desc[i].type == GD_TYPE_STRING)
+      {
+       // strings are treated different, as occupy the whole length of the line
+       gd_strcpy(value, param);
+
+       // remember this to skip checking the number of parameters at the end of the function
+       was_string = TRUE;
+
+       continue;
+      }
+
+      if (prop_desc[i].type == GD_TYPE_LONGSTRING)
+      {
+       char **str = (char **)value;
+
+       checked_free(*str);
+       *str = getUnescapedString(param);
+
+       // remember this to skip checking the number of parameters at the end of the function
+       was_string = TRUE;
+
+       continue;
+      }
+
+      // not a string, so use scanf calls
+      // ALSO, if no more parameters to process, exit loop
+      for (j = 0; j < prop_desc[i].count && params[paramindex] != NULL; j++)
+      {
+       boolean success = FALSE;
+       double res;
+
+       switch (prop_desc[i].type)
+       {
+         case GD_TYPE_LONGSTRING:
+         case GD_TYPE_STRING:
+           // handled above
+         case GD_TAB:
+         case GD_LABEL:
+           // do nothing
+           break;
+
+         case GD_TYPE_BOOLEAN:
+           success = sscanf(params[paramindex], "%d", &bvalue[j]) == 1;
+           if (!success)
+           {
+             if (strcasecmp(params[paramindex], "true") == 0 ||
+                 strcasecmp(params[paramindex], "on") == 0 ||
+                 strcasecmp(params[paramindex], "yes") == 0)
+             {
+               bvalue[j] = TRUE;
+               success = TRUE;
+             }
+             else if (strcasecmp(params[paramindex], "false") == 0 ||
+                      strcasecmp(params[paramindex], "off") == 0 ||
+                      strcasecmp(params[paramindex], "no") == 0)
+             {
+               bvalue[j] = FALSE;
+               success = TRUE;
+             }
+           }
+
+           // if we are processing an array, fill other values with these.
+           // if there are other values specified, those will be overwritten.
+           if (success)
+             for (k = j + 1; k < prop_desc[i].count; k++)
+               bvalue[k] = bvalue[j];
+
+           break;
+
+         case GD_TYPE_INT:
+           success = sscanf(params[paramindex], "%d", &ivalue[j]) == 1;
+           if (success)
+             // copy to other if array
+             for (k = j + 1; k < prop_desc[i].count; k++)
+               ivalue[k] = ivalue[j];
+
+           break;
+
+         case GD_TYPE_PROBABILITY:
+           // must be reset before calling strtod() to detect overflow/underflow
+           errno = 0;
+           res = strtod(params[paramindex], NULL);
+           if (errno == 0 && res >= 0 && res <= 1)
+           {
+             // fill all remaining items in array - may be only one
+             for (k = j; k < prop_desc[i].count; k++)
+               // probabilities are stored inside as ppm (1E6)
+               ivalue[k] = res * 1E6 + 0.5;
+
+             success = TRUE;
+           }
+
+           break;
+
+         case GD_TYPE_RATIO:
+           // must be reset before calling strtod() to detect overflow/underflow
+           errno = 0;
+           res = strtod (params[paramindex], NULL);
+           if (errno == 0 && res >= 0 && res <= 1)
+           {
+             for (k = j; k < prop_desc[i].count; k++)
+               ivalue[k] = (int)(res * ratio + 0.5);
+
+             success = TRUE;
+           }
+
+           break;
+
+         case GD_TYPE_ELEMENT:
+           evalue[j] = gd_get_element_from_string(params[paramindex]);
+
+           // copy to all remaining elements in array
+           for (k = j + 1; k < prop_desc[i].count; k++)
+             evalue[k] = evalue[j];
+
+           // this shows error message on its own, do treat as always succeeded
+           success = TRUE;
+           break;
+
+         case GD_TYPE_DIRECTION:
+           dvalue[j] = gd_direction_from_string(params[paramindex]);
+           // copy to all remaining items in array
+           for (k = j + 1; k < prop_desc[i].count; k++)
+             dvalue[k] = dvalue[j];
+
+           success = TRUE;
+           break;
+
+         case GD_TYPE_SCHEDULING:
+           svalue[j] = gd_scheduling_from_string(params[paramindex]);
+           // copy to all remaining items in array
+           for (k = j + 1; k < prop_desc[i].count; k++)
+             svalue[k] = svalue[j];
+
+           // if there was an error, already reported by gd_scheduling_from_string
+           success = TRUE;
+           break;
+
+         case GD_TYPE_COLOR:
+         case GD_TYPE_EFFECT:
+           // shoud have handled this elsewhere
+           break;
+       }
+
+       if (success)
+         paramindex++;    // go to next parameter to process
+       else
+         Warn("invalid parameter '%s' for attribute %s", params[paramindex], attrib);
+      }
+    }
+  }
+
+  // if we found the identifier, but still could not process all parameters...
+  // of course, not for strings, as the whole line is the string
+  if (identifier_found && !was_string && paramindex < paramcount)
+    Warn("excess parameters for attribute '%s': '%s'", attrib, params[paramindex]);
+
+  freeStringArray(params);
+
+  return identifier_found;
+}
+
+
+// ============================================================================
+// BDCFF LOADING
+// ============================================================================
+
+static boolean replay_store_more_from_bdcff(GdReplay *replay, const char *param)
+{
+  char **split;
+  int i;
+  boolean result = TRUE;
+
+  split = getSplitStringArray(param, " ", -1);
+
+  for (i = 0; split[i] != 0; i++)
+    result = result && replay_store_from_bdcff(replay, split[i]);
+
+  freeStringArray(split);
+
+  return result;
+}
+
+// report all remaining tags; called after the above function.
+static void replay_report_unknown_tags_func(const char *attrib, const char *param, void *data)
+{
+  Warn("unknown replay tag '%s'", attrib);
+}
+
+// a GHashTable foreach func.
+// keys are attribs; values are params;
+// the user data is the cave the hash table belongs to.
+static boolean replay_process_tags_func(const char *attrib, const char *param, GdReplay *replay)
+{
+  boolean identifier_found = FALSE;
+
+  // movements
+  if (strcasecmp(attrib, "Movements") == 0)
+  {
+    identifier_found = TRUE;
+    replay_store_more_from_bdcff(replay, param);
+  }
+  else
+  {
+    // any other tag
+    // 0: for ratio types; not used
+    identifier_found = struct_set_property(replay, gd_replay_properties,
+                                          attrib, param, 0);
+  }
+
+  // a ghrfunc should return true if the identifier is to be removed
+  return identifier_found;
+}
+
+// ...
+static void replay_process_tags(GdReplay *replay, HashTable *tags)
+{
+  // process all tags
+  hashtable_foreach_remove(tags, (hashtable_remove_fn)replay_process_tags_func, replay);
+}
+
+// a GHashTable foreach func.
+// keys are attribs; values are params;
+// the user data is the cave the hash table belongs to.
+static boolean cave_process_tags_func(const char *attrib, const char *param, GdCave *cave)
+{
+  char **params;
+  int paramcount;
+  boolean identifier_found;
+
+  params = getSplitStringArray(param, " ", -1);
+  paramcount = getStringArrayLength(params);
+  identifier_found = FALSE;
+
+  if (strcasecmp(attrib, "SnapExplosions") == 0)
+  {
+    // handle compatibility with old snapexplosions flag
+
+    identifier_found = TRUE;
+
+    if (strcasecmp(param, "true") == 0)
+    {
+      cave->snap_element = O_EXPLODE_1;
+    }
+    else if (strcasecmp(param, "false") == 0)
+    {
+      cave->snap_element = O_SPACE;
+    }
+    else
+    {
+      Warn("invalid param for '%s': '%s'", attrib, param);
+    }
+  }
+  else if (strcasecmp(attrib, "BD1Scheduling") == 0)
+  {
+    // handle compatibility with old bd1scheduling flag
+
+    identifier_found = TRUE;
+
+    if (strcasecmp(param, "true") == 0)
+    {
+      if (cave->scheduling == GD_SCHEDULING_PLCK)
+       cave->scheduling = GD_SCHEDULING_BD1;
+    }
+  }
+  else if (strcasecmp(attrib, "Engine") == 0)
+  {
+    // handle bdcff engine flag
+
+    identifier_found = TRUE;
+
+    GdEngine engine = gd_cave_get_engine_from_string(param);
+
+    if (engine == GD_ENGINE_INVALID)
+      Warn(_("invalid parameter \"%s\" for attribute %s"), param, attrib);
+    else
+      gd_cave_set_engine_defaults(cave, engine);
+  }
+  else if (strcasecmp(attrib, "AmoebaProperties") == 0)
+  {
+    // handle compatibility with old AmoebaProperties flag
+
+    GdElement elem1 = O_STONE, elem2 = O_DIAMOND;
+
+    identifier_found = TRUE;
+    elem1 = gd_get_element_from_string(params[0]);
+    elem2 = gd_get_element_from_string(params[1]);
+    cave->amoeba_too_big_effect = elem1;
+    cave->amoeba_enclosed_effect = elem2;
+  }
+  else if (strcasecmp(attrib, "Colors") == 0)
+  {
+    // colors attribute is a mess, have to process explicitly
+    boolean ok = TRUE;
+
+    // Colors = [border background] foreground1 foreground2 foreground3 [amoeba slime]
+    identifier_found = TRUE;
+
+    if (paramcount == 3)
+    {
+      // only color1,2,3
+      cave->colorb = gd_c64_color(0);   // border - black
+      cave->color0 = gd_c64_color(0);   // background - black
+      cave->color1 = gd_color_get_from_string(params[0]);
+      cave->color2 = gd_color_get_from_string(params[1]);
+      cave->color3 = gd_color_get_from_string(params[2]);
+      cave->color4 = cave->color3;      // amoeba
+      cave->color5 = cave->color1;      // slime
+    }
+    else if (paramcount == 5)
+    {
+      // bg,color0,1,2,3
+      cave->colorb = gd_color_get_from_string(params[0]);
+      cave->color0 = gd_color_get_from_string(params[1]);
+      cave->color1 = gd_color_get_from_string(params[2]);
+      cave->color2 = gd_color_get_from_string(params[3]);
+      cave->color3 = gd_color_get_from_string(params[4]);
+      cave->color4 = cave->color3;      // amoeba
+      cave->color5 = cave->color1;      // slime
+    }
+    else if (paramcount == 7)
+    {
+      // bg,color0,1,2,3,amoeba,slime
+      cave->colorb = gd_color_get_from_string(params[0]);
+      cave->color0 = gd_color_get_from_string(params[1]);
+      cave->color1 = gd_color_get_from_string(params[2]);
+      cave->color2 = gd_color_get_from_string(params[3]);
+      cave->color3 = gd_color_get_from_string(params[4]);
+      cave->color4 = gd_color_get_from_string(params[5]);    // amoeba
+      cave->color5 = gd_color_get_from_string(params[6]);    // slime
+    }
+    else
+    {
+      Warn("invalid number of color strings: %s", param);
+
+      ok = FALSE;
+    }
+
+    // now check and maybe make up some new.
+    if (!ok ||
+       gd_color_is_unknown(cave->colorb) ||
+       gd_color_is_unknown(cave->color0) ||
+       gd_color_is_unknown(cave->color1) ||
+       gd_color_is_unknown(cave->color2) ||
+       gd_color_is_unknown(cave->color3) ||
+       gd_color_is_unknown(cave->color4) ||
+       gd_color_is_unknown(cave->color5))
+    {
+      Warn("created a new C64 color scheme.");
+
+      gd_cave_set_random_c64_colors(cave);    // just create some random
+    }
+  }
+  else
+  {
+    identifier_found = struct_set_property(cave, gd_cave_properties, attrib, param, cave->w * cave->h);
+  }
+
+  freeStringArray(params);
+
+  // a ghrfunc should return true if the identifier is to be removed
+  return identifier_found;
+}
+
+// report all remaining tags; called after the above function.
+static void cave_report_and_copy_unknown_tags_func(char *attrib, char *param, void *data)
+{
+  GdCave *cave = (GdCave *)data;
+
+  Warn("unknown tag '%s'", attrib);
+
+  hashtable_insert(cave->tags, getStringCopy(attrib), getStringCopy(param));
+}
+
+// having read all strings belonging to the cave, process it.
+static void cave_process_tags(GdCave *cave, HashTable *tags, List *maplines)
+{
+  char *value;
+
+  // first check cave name, so we can report errors correctly (saying that GdCave xy: error foobar)
+  value = hashtable_search(tags, "Name");
+  if (value)
+    cave_process_tags_func("Name", value, cave);
+
+  // process lame engine tag first so its settings may be overwritten later
+  value = hashtable_search(tags, "Engine");
+  if (value)
+  {
+    cave_process_tags_func("Engine", value, cave);
+    hashtable_remove(tags, "Engine");
+  }
+
+  // check if this is an intermission, so we can set to cavesize or intermissionsize
+  value = hashtable_search(tags, "Intermission");
+  if (value)
+  {
+    cave_process_tags_func("Intermission", value, cave);
+    hashtable_remove(tags, "Intermission");
+  }
+
+  if (cave->intermission)
+  {
+    // set to IntermissionSize
+    cave->w  = intermissionsize[0];
+    cave->h  = intermissionsize[1];
+    cave->x1 = intermissionsize[2];
+    cave->y1 = intermissionsize[3];
+    cave->x2 = intermissionsize[4];
+    cave->y2 = intermissionsize[5];
+  }
+  else
+  {
+    // set to CaveSize
+    cave->w = cavesize[0];
+    cave->h = cavesize[1];
+    cave->x1 = cavesize[2];
+    cave->y1 = cavesize[3];
+    cave->x2 = cavesize[4];
+    cave->y2 = cavesize[5];
+  }
+
+  // process size at the beginning... as ratio types depend on this.
+  value = hashtable_search(tags, "Size");
+  if (value)
+  {
+    cave_process_tags_func("Size", value, cave);
+    hashtable_remove(tags, "Size");
+  }
+
+  // these are read from the hash table, but also have some implications
+  // we do not delete them from the hash table here; as _their values will be processed later_.
+  // here we only set their implicite meanings.
+  // these also set predictability
+  if (hashtable_search(tags, "SlimePermeability"))
+    cave->slime_predictable = FALSE;
+
+  if (hashtable_search(tags, "SlimePermeabilityC64"))
+    cave->slime_predictable = TRUE;
+
+  // these set scheduling type.
+  // framedelay takes precedence, if there are both; so we check it later.
+  if (hashtable_search(tags, "CaveDelay"))
+  {
+    // only set scheduling type, when it is not the gdash-default.
+    // this allows settings cavescheduling = bd1 in the [game] section, for example.
+    // in that case, this one will not overwrite it.
+    if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
+      cave->scheduling = GD_SCHEDULING_PLCK;
+  }
+
+  // but if the cave has a frametime setting, always switch to milliseconds.
+  if (hashtable_search(tags, "FrameTime"))
+    cave->scheduling = GD_SCHEDULING_MILLISECONDS;
+
+  // process all tags
+  hashtable_foreach_remove(tags, (hashtable_remove_fn)cave_process_tags_func, cave);
+
+  // and at the end, when read all tags (especially the size= tag)
+  // process map, if any.
+  // only report if map read is bigger than size= specified.
+  // some old bdcff files use smaller intermissions than the one specified.
+  if (maplines)
+  {
+    int x, y, length = list_length(maplines);
+    List *iter;
+
+    // create map and fill with initial border, in case that map strings are shorter or somewhat
+    cave->map = gd_cave_map_new(cave, GdElement);
+
+    for (y = 0; y < cave->h; y++)
+      for (x = 0; x < cave->w; x++)
+       cave->map[y][x] = cave->initial_border;
+
+    if (length != cave->h && length != (cave->y2-cave->y1 + 1))
+      Warn("map error: cave height = %d (%d visible), map height = %d",
+          cave->h, cave->y2 - cave->y1 + 1, length);
+
+    for (iter = maplines, y = 0; y < length && iter != NULL; iter = iter->next, y++)
+    {
+      const char *line = iter->data;
+      int slen = strlen(line);
+
+      if (slen != cave->w && slen != (cave->x2 - cave->x1 + 1))
+       Warn("map error in row %d: cave width = %d (%d visible), map width = %d",
+            y, cave->w, cave->x2 - cave->x1 + 1, slen);
+
+      // use number of cells from cave or string, whichever is smaller.
+      // so will not overwrite array!
+      for (x = 0; x < MIN(cave->w, slen); x++)
+       cave->map[y][x] = gd_get_element_from_character (line[x]);
+    }
+  }
+}
+
+// sets the cavesize array to default values
+static void set_cavesize_defaults(void)
+{
+  cavesize[0] = 40;
+  cavesize[1] = 22;
+  cavesize[2] = 0;
+  cavesize[3] = 0;
+  cavesize[4] = 39;
+  cavesize[5] = 21;
+}
+
+// sets the cavesize array to default values
+static void set_intermissionsize_defaults(void)
+{
+  intermissionsize[0] = 40;
+  intermissionsize[1] = 22;
+  intermissionsize[2] = 0;
+  intermissionsize[3] = 0;
+  intermissionsize[4] = 19;
+  intermissionsize[5] = 11;
+}
+
+boolean gd_caveset_load_from_bdcff(const char *contents)
+{
+  char **lines;
+  int lineno;
+  GdCave *cave;
+  List *iter;
+  boolean reading_replay = FALSE;
+  boolean reading_map = FALSE;
+  boolean reading_mapcodes = FALSE;
+  boolean reading_highscore = FALSE;
+  boolean reading_objects = FALSE;
+  boolean reading_bdcff_demo = FALSE;
+  // assume version to be 0.32, also when the file does not specify it explicitly
+  GdString version_read = "0.32";
+  List *mapstrings = NULL;
+  int linenum;
+  HashTable *tags, *replay_tags;
+  GdObjectLevels levels = GD_OBJECT_LEVEL_ALL;
+  GdCave *default_cave;
+
+  gd_caveset_clear();
+
+  set_cavesize_defaults();
+  set_intermissionsize_defaults();
+  gd_create_char_to_element_table();
+
+  tags        = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
+  replay_tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
+
+  // split into lines
+  lines = getSplitStringArray (contents, "\n", 0);
+
+  // attributes read will be set in cave. if no [cave]; they are stored
+  // in the default cave; like in a [game] */
+  default_cave = gd_cave_new();
+  cave = default_cave;
+
+  linenum = getStringArrayLength(lines);
+
+  for (lineno = 0; lineno < linenum; lineno++)
+  {
+    char *line = lines[lineno];
+    char *r;
+
+    // remove windows-nightmare \r-s
+    while ((r = strchr(line, '\r')))
+      strcpy(r, r + 1);
+
+    // skip empty lines
+    if (strlen(line) == 0)
+      continue;
+
+    // just skip comments. be aware that map lines may start with a semicolon...
+    if (!reading_map && line[0] == ';')
+      continue;
+
+    // STARTING WITH A BRACKET [ IS A SECTION
+    if (line[0] == '[')
+    {
+      if (strcasecmp(line, "[cave]") == 0)
+      {
+       // new cave
+       if (mapstrings)
+       {
+         Warn("incorrect file format: new [cave] section, but already read some map lines");
+         list_free(mapstrings);
+         mapstrings = NULL;
+       }
+
+       // process any pending tags for game ...
+       cave_process_tags(default_cave, tags, NULL);
+
+       // ... to be able to create a copy for a new cave.
+       cave = gd_cave_new_from_cave(default_cave);
+       gd_caveset = list_append (gd_caveset, cave);
+      }
+      else if (strcasecmp(line, "[/cave]") == 0)
+      {
+       cave_process_tags(cave, tags, mapstrings);
+       list_free(mapstrings);
+       mapstrings = NULL;
+
+       hashtable_foreach(tags, (hashtable_fn)cave_report_and_copy_unknown_tags_func, cave);
+       hashtable_remove_all(tags);
+
+       // set this to point the pseudo-cave which holds default values
+       cave = default_cave;
+      }
+      else if (strcasecmp(line, "[map]") == 0)
+      {
+       reading_map = TRUE;
+       if (mapstrings != NULL)
+       {
+         Warn("incorrect file format: new [map] section, but already read some map lines");
+         list_free(mapstrings);
+         mapstrings = NULL;
+       }
+      }
+      else if (strcasecmp(line, "[/map]") == 0)
+      {
+       reading_map = FALSE;
+      }
+      else if (strcasecmp(line, "[mapcodes]") == 0)
+      {
+       reading_mapcodes = TRUE;
+      }
+      else if (strcasecmp(line, "[/mapcodes]") == 0)
+      {
+       reading_mapcodes = FALSE;
+      }
+      else if (strcasecmp(line, "[highscore]") == 0)
+      {
+       reading_highscore = TRUE;
+      }
+      else if (strcasecmp(line, "[/highscore]") == 0)
+      {
+       reading_highscore = FALSE;
+      }
+      else if (strcasecmp(line, "[objects]") == 0)
+      {
+       reading_objects = TRUE;
+      }
+      else if (strcasecmp(line, "[/objects]") == 0)
+      {
+       reading_objects = FALSE;
+      }
+      else if (strcasecmp(line, "[demo]") == 0)
+      {
+       GdReplay *replay;
+
+       reading_bdcff_demo = TRUE;
+
+       if (cave != default_cave)
+       {
+         replay = gd_replay_new();
+         replay->saved = TRUE;
+         replay->success = TRUE;   // we think that it is a successful demo
+         cave->replays = list_append(cave->replays, replay);
+         gd_strcpy(replay->player_name, "???");    // name not saved
+       }
+       else
+       {
+         Warn("[demo] section must be in [cave] section!");
+       }
+      }
+      else if (strcasecmp(line, "[/demo]") == 0)
+      {
+       reading_bdcff_demo = FALSE;
+      }
+      else if (strcasecmp(line, "[replay]") == 0)
+      {
+       reading_replay = TRUE;
+      }
+      else if (strcasecmp(line, "[/replay]") == 0)
+      {
+       GdReplay *replay;
+
+       reading_replay = FALSE;
+       replay = gd_replay_new();
+
+       // set "saved" flag, so this replay will be written when the caveset is saved again
+       replay->saved = TRUE;
+       replay_process_tags(replay, replay_tags);
+
+#if 1
+       // BDCFF numbers levels from 1 to 5, but internally we number levels from 0 to 4
+       if (replay->level > 0)
+         replay->level--;
+#endif
+
+       // report any remaining unknown tags
+       hashtable_foreach(replay_tags, (hashtable_fn)replay_report_unknown_tags_func, NULL);
+       hashtable_remove_all(replay_tags);
+
+       if (replay->movements->len != 0)
+       {
+         cave->replays = list_append(cave->replays, replay);
+       }
+       else
+       {
+         Warn("no movements in replay!");
+         gd_replay_free(replay);
+       }
+      }
+      // GOSH i hate bdcff
+      else if (strncasecmp(line, "[level=", strlen("[level=")) == 0)
+      {
+       int l[5];
+       int num;
+       char *nums;
+
+       // there IS an equal sign, and we also skip that, so this points to the numbers
+       nums = strchr(line, '=') + 1;
+       num = sscanf(nums, "%d,%d,%d,%d,%d", l + 0, l + 1, l + 2, l + 3, l + 4);
+       levels = 0;
+
+       if (num == 0)
+       {
+         Warn("invalid Levels tag: %s", line);
+         levels = GD_OBJECT_LEVEL_ALL;
+       }
+       else
+       {
+         int n;
+
+         for (n = 0; n < num; n++)
+         {
+           if (l[n] <= 5 && l[n] >= 1)
+             levels |= gd_levels_mask[l[n] - 1];
+           else
+             Warn("invalid level number %d", l[n]);
+         }
+       }
+      }
+      else if (strcasecmp(line, "[/level]") == 0)
+      {
+       levels = GD_OBJECT_LEVEL_ALL;
+      }
+      else if (strcasecmp(line, "[game]") == 0)
+      {
+      }
+      else if (strcasecmp(line, "[/game]") == 0)
+      {
+      }
+      else if (strcasecmp(line, "[BDCFF]") == 0)
+      {
+      }
+      else if (strcasecmp(line, "[/BDCFF]") == 0)
+      {
+      }
+      else
+      {
+       Warn("unknown section: \"%s\"", line);
+      }
+
+      continue;
+    }
+
+    if (reading_map)
+    {
+      // just append to the mapstrings list. we will process it later
+      mapstrings = list_append(mapstrings, line);
+
+      continue;
+    }
+
+    // strip leading and trailing spaces AFTER checking if we are reading a map.
+    // map lines might begin or end with spaces */
+    stripString(line);
+
+    if (reading_highscore)
+    {
+      int score;
+
+      if (sscanf(line, "%d", &score) != 1 || strchr(line, ' ') == NULL)
+      {
+       // first word is the score
+       Warn("highscore format incorrect");
+      }
+      else
+      {
+       if (cave == default_cave)
+         // if we are reading the [game], add highscore to that one.
+         // from first space: the name
+         gd_add_highscore(gd_caveset_data->highscore, strchr(line, ' ') + 1, score);
+       else
+         // if a cave, add highscore to that.
+         gd_add_highscore(cave->highscore, strchr(line, ' ') + 1, score);
+      }
+
+      continue;
+    }
+
+    // read bdcff-style [demo], similar to a complete replay but cannot store like anything
+    if (reading_bdcff_demo)
+    {
+      GdReplay *replay;
+      List *iter;
+
+      // demo must be in [cave] section. we already showed an error message for this.
+      if (cave == default_cave)
+       continue;
+
+      iter = list_last(cave->replays);
+
+      replay = (GdReplay *)iter->data;
+      replay_store_more_from_bdcff(replay, line);
+
+      continue;
+    }
+
+    if (reading_objects)
+    {
+      GdObject *new_object;
+
+      new_object = gd_object_new_from_string(line);
+      if (new_object)
+      {
+       new_object->levels = levels;    // apply levels to new object
+       cave->objects = list_append(cave->objects, new_object);
+      }
+      else
+      {
+       Error("invalid object specification: %s", line);
+      }
+
+      continue;
+    }
+
+    // has an equal sign ->  some_attrib = parameters  type line.
+    if (strchr (line, '=') != NULL)
+    {
+      char *attrib, *param;
+
+      attrib = line;                   // attrib is from the first char
+      param = strchr(line, '=') + 1;   // param is after equal sign
+      *strchr (line, '=') = 0;         // delete equal sign - line is therefore splitted
+
+      // own tag: not too much thinking :P
+      if (reading_replay)
+      {
+       hashtable_insert(replay_tags, getStringCopy(attrib), getStringCopy(param));
+      }
+      else if (reading_mapcodes)
+      {
+       if (strcasecmp("Length", attrib) == 0)
+       {
+         // we do not support map code width != 1
+         if (strcmp(param, "1") != 0)
+           Warn(_("Only one-character map codes are currently supported!"));
+       }
+       else
+       {
+         // the first character of the attribute is the element code itself
+         gd_char_to_element[(int)attrib[0]] = gd_get_element_from_string(param);
+       }
+      }
+      else if (strcasecmp("Version", attrib) == 0)
+      {
+       // BDCFF version
+       gd_strcpy(version_read, param);
+      }
+      else if (strcasecmp(attrib, "Caves") == 0)
+      {
+       // CAVES = x
+
+       // BDCFF files sometimes state how many caves they have
+       // we ignore this field.
+      }
+      else if (strcasecmp(attrib, "Levels") == 0)
+      {
+       // LEVELS = x
+
+       // BDCFF files sometimes state how many levels they have
+       // we ignore this field.
+      }
+      else if (strcasecmp(attrib, "CaveSize") == 0)
+      {
+       int i;
+
+       i = sscanf(param, "%d %d %d %d %d %d",
+                  cavesize + 0,
+                  cavesize + 1,
+                  cavesize + 2,
+                  cavesize + 3,
+                  cavesize + 4,
+                  cavesize + 5);
+
+       // allowed: 2 or 6 numbers
+       if (i == 2)
+       {
+         cavesize[2] = 0;
+         cavesize[3] = 0;
+         cavesize[4] = cavesize[0]-1;
+         cavesize[5] = cavesize[1]-1;
+       }
+       else if (i != 6)
+       {
+         set_cavesize_defaults();
+         Warn("invalid CaveSize tag: %s", line);
+       }
+      }
+      else if (strcasecmp(attrib, "IntermissionSize") == 0)
+      {
+       int i;
+
+       i = sscanf(param, "%d %d %d %d %d %d",
+                  intermissionsize + 0,
+                  intermissionsize + 1,
+                  intermissionsize + 2,
+                  intermissionsize + 3,
+                  intermissionsize + 4,
+                  intermissionsize + 5);
+
+       // allowed: 2 or 6 numbers
+       if (i == 2)
+       {
+         intermissionsize[2] = 0;
+         intermissionsize[3] = 0;
+         intermissionsize[4] = intermissionsize[0]-1;
+         intermissionsize[5] = intermissionsize[1]-1;
+       }
+       else if (i != 6)
+       {
+         set_intermissionsize_defaults();
+         Warn("invalid IntermissionSize tag: '%s'", line);
+       }
+      }
+      else if (strcasecmp(attrib, "Effect") == 0)
+      {
+       // CHECK IF IT IS AN EFFECT
+       char **params;
+
+       params = getSplitStringArray(param, " ", -1);
+
+       // an effect command has two parameters
+       if (getStringArrayLength(params) == 2)
+       {
+         int i;
+
+         for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
+         {
+           // we have to search for this effect
+           if (gd_cave_properties[i].type == GD_TYPE_EFFECT &&
+               strcasecmp(params[0], gd_cave_properties[i].identifier) == 0)
+           {
+             // found identifier
+             void *value = STRUCT_MEMBER_P (cave, gd_cave_properties[i].offset);
+
+             *((GdElement *) value) = gd_get_element_from_string (params[1]);
+             break;
+           }
+         }
+
+         // if we didn't find first element name
+         if (gd_cave_properties[i].identifier == NULL)
+         {
+           // for compatibility with tim stridmann's memorydump->bdcff converter... .... ...
+           if (strcasecmp(params[0], "BOUNCING_BOULDER") == 0)
+             cave->stone_bouncing_effect = gd_get_element_from_string (params[1]);
+           else if (strcasecmp(params[0], "EXPLOSION3S") == 0)
+             cave->explosion_effect = gd_get_element_from_string(params[1]);
+           // falling with one l...
+           else if (strcasecmp(params[0], "STARTING_FALING_DIAMOND") == 0)
+             cave->diamond_falling_effect = gd_get_element_from_string (params[1]);
+           // dirt lookslike
+           else if (strcasecmp(params[0], "DIRT") == 0)
+             cave->dirt_looks_like = gd_get_element_from_string (params[1]);
+           else if (strcasecmp(params[0], "HEXPANDING_WALL") == 0 &&
+                    strcasecmp(params[1], "STEEL_HEXPANDING_WALL") == 0)
+           {
+             cave->expanding_wall_looks_like = O_STEEL;
+           }
+           else
+           {
+             // didn't find at all
+             Warn("invalid effect name '%s'", params[0]);
+           }
+         }
+       }
+       else
+       {
+         Warn("invalid effect specification '%s'", param);
+       }
+
+       freeStringArray(params);
+      }
+      else
+      {
+       // no special handling: this is a normal attribute.
+
+       if (cave == default_cave)
+       {
+         // we are reading the [game]
+         if (attrib_is_valid_for_caveset(attrib))
+         {
+           // if it is a caveset attrib, process it for the caveset.
+           struct_set_property(gd_caveset_data, gd_caveset_properties, attrib, param, 0);
+         }
+         else if (attrib_is_valid_for_cave(attrib))
+         {
+           // it must be a default setting for all caves. is it a valid identifier?
+           // yes, it is. add to the hash table, which will be copied for all caves.
+           hashtable_insert(tags, getStringCopy(attrib), getStringCopy(param));
+         }
+         else
+         {
+           // unknown setting - report.
+           Warn("invalid attribute for [game] '%s'", attrib);
+         }
+       }
+       else
+       {
+         // we are reading a [cave]
+         // cave settings are immediately added to cave hash table.
+         // if it is unknown, we have to remember it, and save it again.
+         hashtable_insert(tags, getStringCopy(attrib), getStringCopy(param));
+       }
+      }
+
+      continue;
+    }
+
+    Error("cannot parse line: %s", line);
+  }
+
+  if (mapstrings)
+  {
+    Warn("incorrect file format: end of file, but still have some map lines read");
+    list_free(mapstrings);
+    mapstrings = NULL;
+  }
+
+  // the [game] section had some values which are default if not specified in [cave] sections.
+  // these are used only for loading, so forget them now
+  if (default_cave->map)
+    Warn(_("Invalid BDCFF: [game] section has a map"));
+  if (default_cave->objects)
+    Warn(_("Invalid BDCFF: [game] section has drawing objects defined"));
+
+  // cleanup
+  freeStringArray(lines);
+  hashtable_destroy(tags);
+  hashtable_destroy(replay_tags);
+  gd_cave_free(default_cave);
+
+  // old bdcff files hack. explanation follows.
+  // there were 40x22 caves in c64 bd, intermissions were also 40x22, but the visible
+  // part was the upper left corner, 20x12. 40x22 caves are needed, as 20x12 caves would
+  // look different (random cave elements needs the correct size.)
+  // also, in older bdcff files, there is no size= tag. caves default to 40x22 and 20x12.
+  // even the explicit drawrect and other drawing instructions, which did set up intermissions
+  // to be 20x12, are deleted. very very bad decision.
+  // here we try to detect and correct this.
+
+  if (strEqual(version_read, "0.32"))
+  {
+    List *iter;
+
+    Warn("No BDCFF version, or 0.32. Using unspecified-intermission-size hack.");
+
+    for (iter = gd_caveset; iter != NULL; iter = iter->next)
+    {
+      GdCave *cave = (GdCave *)iter->data;
+
+      // only applies to intermissions; not applied to mapped caves, as maps are filled with
+      // initial border, if the map read is smaller
+      if (cave->intermission && !cave->map)
+      {
+       // we do not set the cave to 20x12, rather to 40x22 with 20x12 visible.
+       GdObject object;
+
+       cave->w = 40;
+       cave->h = 22;
+       cave->x1 = 0;
+       cave->y1 = 0;
+       cave->x2 = 19;
+       cave->y2 = 11;
+
+       // and cover the invisible area
+       object.type = GD_FILLED_RECTANGLE;
+       object.x1 = 0;
+       object.y1 = 11;    // 11, because this will also be the border
+       object.x2 = 39;
+       object.y2 = 21;
+       object.element = cave->initial_border;
+       object.fill_element = cave->initial_border;
+
+       cave->objects = list_prepend(cave->objects, get_memcpy(&object, sizeof(object)));
+
+       object.x1 = 19;
+       object.y1 = 0;    // 19, as it is also the border
+
+       // another
+       cave->objects = list_prepend(cave->objects, get_memcpy(&object, sizeof(object)));
+      }
+    }
+  }
+
+  if (!strEqual(version_read, BDCFF_VERSION))
+    Warn("BDCFF version %s, loaded caveset may have errors.", version_read);
+
+  // check for replays which are problematic
+  for (iter = gd_caveset; iter != NULL; iter = iter->next)
+    gd_cave_check_replays((GdCave *)iter->data, TRUE, FALSE, FALSE);
+
+  // if there was some error message - return fail XXX
+  return TRUE;
+}
+
+
+// ============================================================================
+// BDCFF saving
+// ============================================================================
+
+#define GD_PTR_ARRAY_MINIMUM_INITIAL_SIZE      64
+
+GdPtrArray *gd_ptr_array_sized_new(unsigned int size)
+{
+  GdPtrArray *array = checked_calloc(sizeof(GdPtrArray));
+
+  array->data = checked_calloc(size * sizeof(void *));
+  array->size_allocated = size;
+  array->size_initial = size;
+  array->size = 0;
+
+  return array;
+}
+
+GdPtrArray *gd_ptr_array_new(void)
+{
+  return gd_ptr_array_sized_new(GD_PTR_ARRAY_MINIMUM_INITIAL_SIZE);
+}
+
+void gd_ptr_array_add(GdPtrArray *array, void *data)
+{
+  if (array->size == array->size_allocated)
+  {
+    array->size_allocated += array->size_initial;
+    array->data = checked_realloc(array->data, array->size_allocated * sizeof(void *));
+  }
+
+  array->data[array->size++] = data;
+}
+
+boolean gd_ptr_array_remove(GdPtrArray *array, void *data)
+{
+  int i, j;
+
+  for (i = 0; i < array->size; i++)
+  {
+    if (array->data[i] == data)
+    {
+      checked_free(array->data[i]);
+
+      for (j = i; j < array->size - 1; j++)
+       array->data[j] = array->data[j + 1];
+
+      array->size--;
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+void gd_ptr_array_free(GdPtrArray *array, boolean free_data)
+{
+  int i;
+
+  if (free_data)
+  {
+    for (i = 0; i < array->size; i++)
+      checked_free(array->data[i]);
+  }
+
+  checked_free(array);
+}
+
+// ratio: max cave size for GD_TYPE_RATIO. should be set to cave->w*cave->h when calling
+static void save_properties(GdPtrArray *out, void *str, void *str_def,
+                           const GdStructDescriptor *prop_desc, int ratio)
+{
+  int i, j;
+  boolean parameter_written = FALSE, should_write = FALSE;
+  char *line = NULL;
+  const char *identifier = NULL;
+
+  for (i = 0; prop_desc[i].identifier != NULL; i++)
+  {
+    void *value, *default_value;
+
+    // used only by the gui
+    if (prop_desc[i].type == GD_TAB || prop_desc[i].type == GD_LABEL)
+      continue;
+
+    // these are handled explicitly
+    if (prop_desc[i].flags & GD_DONT_SAVE)
+      continue;
+
+    // string data
+    // write together with identifier, as one string per line.
+    if (prop_desc[i].type == GD_TYPE_STRING)
+    {
+      // treat strings as special - do not even write identifier if no string.
+      char *text = STRUCT_MEMBER_P(str, prop_desc[i].offset);
+
+      if (strlen(text) > 0)
+       gd_ptr_array_add(out, getStringPrint("%s=%s", prop_desc[i].identifier, text));
+
+      continue;
+    }
+
+    // dynamic string: need to escape newlines
+    if (prop_desc[i].type == GD_TYPE_LONGSTRING)
+    {
+      char *string = STRUCT_MEMBER(char *, str, prop_desc[i].offset);
+
+      if (string != NULL && strlen(string) > 0)
+      {
+       char *escaped = getEscapedString(string);
+
+       gd_ptr_array_add(out, getStringPrint("%s=%s", prop_desc[i].identifier, escaped));
+
+       checked_free(escaped);
+      }
+
+      continue;
+    }
+
+    // if identifier differs from the previous, write out the line collected, and start a new one
+    if (identifier == NULL || !strEqual(prop_desc[i].identifier, identifier))
+    {
+      if (should_write)
+      {
+       // write lines only which carry information other than the default settings
+       gd_ptr_array_add(out, getStringCopy(line));
+      }
+
+      if (prop_desc[i].type == GD_TYPE_EFFECT)
+       setStringPrint(&line, "Effect=");
+      else
+       setStringPrint(&line, "%s=", prop_desc[i].identifier);
+
+      parameter_written = FALSE;    // no value written yet
+      should_write = FALSE;
+
+      // remember identifier
+      identifier = prop_desc[i].identifier;
+    }
+
+    // if we always save this identifier, remember now
+    if (prop_desc[i].flags & GD_ALWAYS_SAVE)
+      should_write = TRUE;
+
+    value         = STRUCT_MEMBER_P(str,     prop_desc[i].offset);
+    default_value = STRUCT_MEMBER_P(str_def, prop_desc[i].offset);
+
+    for (j = 0; j < prop_desc[i].count; j++)
+    {
+      // separate values by spaces. of course no space required for the first one
+      if (parameter_written)
+       appendStringPrint(&line, " ");
+
+      parameter_written = TRUE;    // at least one value written, so write space the next time
+
+      switch (prop_desc[i].type)
+      {
+       case GD_TYPE_BOOLEAN:
+         appendStringPrint(&line, "%s", ((boolean *) value)[j] ? "true" : "false");
+         if (((boolean *) value)[j] != ((boolean *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_INT:
+         appendStringPrint(&line, "%d", ((int *) value)[j]);
+         if (((int *) value)[j] != ((int *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_RATIO:
+         appendStringPrint(&line, "%6.5f", ((int *) value)[j] / (double)ratio);
+         if (((int *) value)[j] != ((int *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_PROBABILITY:
+         // probabilities are stored as *1E6
+         appendStringPrint(&line, "%6.5f", ((int *) value)[j] / 1E6);
+
+         if (((double *) value)[j] != ((double *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_ELEMENT:
+         appendStringPrint(&line, "%s", gd_elements[((GdElement *) value)[j]].filename);
+         if (((GdElement *) value)[j] != ((GdElement *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_EFFECT:
+         // for effects, the property identifier is the effect name.
+         // "Effect=" is hardcoded; see above.
+         appendStringPrint(&line, "%s %s", prop_desc[i].identifier,
+                           gd_elements[((GdElement *) value)[j]].filename);
+         if (((GdElement *) value)[j] != ((GdElement *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_COLOR:
+         appendStringPrint(&line, "%s", gd_color_get_string(((GdColor *) value)[j]));
+         should_write = TRUE;
+         break;
+
+       case GD_TYPE_DIRECTION:
+         appendStringPrint(&line, "%s", gd_direction_get_filename(((GdDirection *) value)[j]));
+         if (((GdDirection *) value)[j] != ((GdDirection *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TYPE_SCHEDULING:
+         appendStringPrint(&line, "%s", gd_scheduling_get_filename(((GdScheduling *) value)[j]));
+         if (((GdScheduling *) value)[j] != ((GdScheduling *) default_value)[j])
+           should_write = TRUE;
+         break;
+
+       case GD_TAB:
+       case GD_LABEL:
+         // used by the editor ui
+         break;
+
+       case GD_TYPE_STRING:
+       case GD_TYPE_LONGSTRING:
+         // never reached
+         break;
+      }
+    }
+  }
+
+  // write remaining data
+  if (should_write)
+    gd_ptr_array_add(out, getStringCopy(line));
+
+  checked_free(line);
+}
+
+// remove a line from the list of strings.
+// the prefix should be a property; add an equal sign! so properties which have names like
+// "slime" and "slimeproperties" won't match each other.
+static void cave_properties_remove(GdPtrArray *out, const char *prefix)
+{
+  int i;
+
+  if (!strSuffix(prefix, "="))
+    Warn("string '%s' should have suffix '='", prefix);
+
+  // search for strings which match, and set them to NULL.
+  // also free them.
+  for (i = 0; i < out->size; i++)
+  {
+    if (strPrefix(gd_ptr_array_index(out, i), prefix))
+    {
+      checked_free(gd_ptr_array_index(out, i));
+      gd_ptr_array_index(out, i) = NULL;
+    }
+  }
+
+  // remove all "null" occurrences
+  while (gd_ptr_array_remove(out, NULL))
+    ;
+}
+
+// output properties of a structure to a file.
+// list_foreach func, so "out" is the last parameter!
+static void caveset_save_cave_func(GdCave *cave, GdPtrArray *out)
+{
+  GdCave *default_cave;
+  GdPtrArray *this_out;
+  char *line = NULL;    // used for various purposes
+  int i;
+
+  gd_ptr_array_add(out, getStringCopy(""));
+  gd_ptr_array_add(out, getStringCopy("[cave]"));
+
+  // first add the properties to a local ptr array.
+  // later, some are deleted (slime permeability, for example) - this is needed because of the
+  //                                                             inconsistencies of the bdcff.
+  // finally, remaining will be added to the normal "out" array.
+  this_out = gd_ptr_array_new();
+
+  default_cave = gd_cave_new();
+  save_properties(this_out, cave, default_cave, gd_cave_properties, cave->w * cave->h);
+  gd_cave_free(default_cave);
+
+  // properties which are handled explicitly. these cannot be handled easily above,
+  // as they have some special meaning. for example, slime_permeability=x sets permeability to
+  // x, and sets predictable to false. bdcff format is simply inconsistent in these aspects.
+
+  // slime permeability is always set explicitly, as it also sets predictability.
+  if (cave->slime_predictable)
+    // if slime is predictable, remove permeab. flag, as that would imply unpredictable slime.
+    cave_properties_remove(this_out, "SlimePermeability=");
+  else
+    // if slime is UNpredictable, remove permeabc64 flag, as that would imply predictable slime.
+    cave_properties_remove(this_out, "SlimePermeabilityC64=");
+
+  // add tags to output, and free local array
+  for (i = 0; i < this_out->size; i++)
+    gd_ptr_array_add(out, gd_ptr_array_index(this_out, i));
+
+  // do not free data pointers, which were just added to array "out"
+  gd_ptr_array_free(this_out, FALSE);
+
+#if 0
+  // save unknown tags as they are
+  if (cave->tags)
+  {
+    List *hashkeys;
+    List *iter;
+
+    hashkeys = g_hash_table_get_keys(cave->tags);
+    for (iter = hashkeys; iter != NULL; iter = iter->next)
+    {
+      gchar *key = (gchar *)iter->data;
+
+      gd_ptr_array_add(out, getStringPrint("%s=%s", key, (const char *) g_hash_table_lookup(cave->tags, key)));
+    }
+
+    list_free(hashkeys);
+  }
+#endif
+
+  // map
+  if (cave->map)
+  {
+    int x, y;
+
+    gd_ptr_array_add(out, getStringCopy(""));
+    gd_ptr_array_add(out, getStringCopy("[map]"));
+
+    line = checked_calloc(cave->w + 1);
+
+    // save map
+    for (y = 0; y < cave->h; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       // check if character is non-zero;
+       // the ...save() should have assigned a character to every element
+       if (gd_elements[cave->map[y][x]].character_new == 0)
+         Warn("gd_elements[cave->map[y][x]].character_new should be non-zero");
+
+       line[x] = gd_elements[cave->map[y][x]].character_new;
+      }
+
+      gd_ptr_array_add(out, getStringCopy(line));
+    }
+
+    gd_ptr_array_add(out, getStringCopy("[/map]"));
+  }
+
+  // save drawing objects
+  if (cave->objects)
+  {
+    List *listiter;
+
+    gd_ptr_array_add(out, getStringCopy(""));
+    gd_ptr_array_add(out, getStringCopy("[objects]"));
+
+    for (listiter = cave->objects; listiter; listiter = list_next(listiter))
+    {
+      GdObject *object = listiter->data;
+      char *text;
+
+      // not for all levels?
+      if (object->levels != GD_OBJECT_LEVEL_ALL)
+      {
+       int i;
+       boolean once;    // true if already written one number
+
+       setStringPrint(&line, "[Level=");
+       once = FALSE;
+
+       for (i = 0; i < 5; i++)
+       {
+         if (object->levels & gd_levels_mask[i])
+         {
+           if (once)    // if written at least one number so far, we need a comma
+             appendStringPrint(&line, ",");
+
+           appendStringPrint(&line, "%d", i+1);
+           once = TRUE;
+         }
+       }
+
+       appendStringPrint(&line, "]");
+       gd_ptr_array_add(out, getStringCopy(line));
+      }
+
+      text = gd_object_get_bdcff(object);
+      gd_ptr_array_add(out, getStringCopy(text));
+      checked_free(text);
+
+      if (object->levels != GD_OBJECT_LEVEL_ALL)
+       gd_ptr_array_add(out, getStringCopy("[/Level]"));
+    }
+
+    gd_ptr_array_add(out, getStringCopy("[/objects]"));
+  }
+
+  gd_ptr_array_add(out, getStringCopy("[/cave]"));
+
+  checked_free(line);
+}
+
+// save cave in bdcff format.
+// "out" will be added lines of bdcff description.
+GdPtrArray *gd_caveset_save_to_bdcff(void)
+{
+  GdPtrArray *out = gd_ptr_array_sized_new(512);
+  GdCavesetData *default_caveset;
+  boolean write_mapcodes = FALSE;
+  List *iter;
+  int i;
+
+  // check if we need an own mapcode table ------
+  // copy original characters to character_new fields; new elements will be added to that one
+  for (i = 0; i < O_MAX; i++)
+    gd_elements[i].character_new = gd_elements[i].character;
+
+  // also regenerate this table as we use it
+  gd_create_char_to_element_table();
+
+  // check all caves
+  for (iter = gd_caveset; iter != NULL; iter = iter->next)
+  {
+    GdCave *cave = (GdCave *)iter->data;
+
+    // if they have a map (random elements+object based maps do not need characters)
+    if (cave->map)
+    {
+      int x, y;
+
+      // check every element of map
+      for(y = 0; y < cave->h; y++)
+       for (x = 0; x < cave->w; x++)
+       {
+         GdElement e = cave->map[y][x];
+
+         // if no character assigned
+         if (gd_elements[e].character_new == 0)
+         {
+           int j;
+
+           // we found at least one, so later we have to write the mapcodes
+           write_mapcodes = TRUE;
+
+           // find a character which is not yet used for any element
+           for (j = 32; j < 128; j++)
+           {
+             // the string contains the characters which should not be used.
+             if (strchr("<>&[]/=\\", j) == NULL && gd_char_to_element[j] == O_UNKNOWN)
+               break;
+           }
+
+           // if no more space... XXX we should rather report to the user
+           if (j == 128)
+             Warn("variable j should be != 128");
+
+           gd_elements[e].character_new = j;
+
+           // we also record to this table, as we use it ^^ a few lines above
+           gd_char_to_element[j] = e;
+         }
+       }
+    }
+  }
+
+  gd_ptr_array_add(out, getStringCopy("[BDCFF]"));
+  gd_ptr_array_add(out, getStringPrint("Version=%s", BDCFF_VERSION));
+
+  // this flag was set above if we need to write mapcodes
+  if (write_mapcodes)
+  {
+    int i;
+
+    gd_ptr_array_add(out, getStringCopy("[mapcodes]"));
+    gd_ptr_array_add(out, getStringCopy("Length=1"));
+
+    for (i = 0; i < O_MAX; i++)
+    {
+      // if no character assigned by specification BUT (AND) we assigned one
+      if (gd_elements[i].character == 0 && gd_elements[i].character_new != 0)
+       gd_ptr_array_add(out, getStringPrint("%c=%s", gd_elements[i].character_new, gd_elements[i].filename));
+    }
+
+    gd_ptr_array_add(out, getStringCopy("[/mapcodes]"));
+  }
+
+  gd_ptr_array_add(out, getStringCopy("[game]"));
+
+  default_caveset = gd_caveset_data_new();
+  save_properties(out, gd_caveset_data, default_caveset, gd_caveset_properties, 0);
+  gd_caveset_data_free(default_caveset);
+  gd_ptr_array_add(out, getStringCopy("Levels=5"));
+
+  list_foreach(gd_caveset, (list_fn)caveset_save_cave_func, out);
+
+  gd_ptr_array_add(out, getStringCopy("[/game]"));
+  gd_ptr_array_add(out, getStringCopy("[/BDCFF]"));
+
+  // saved to ptrarray
+  return out;
+}
diff --git a/src/game_bd/bd_bdcff.h b/src/game_bd/bd_bdcff.h
new file mode 100644 (file)
index 0000000..c12c875
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_BDCFF_H
+#define BD_BDCFF_H
+
+typedef struct _gd_ptr_array
+{
+  void **data;
+  unsigned int size;
+  unsigned int size_initial;
+  unsigned int size_allocated;
+} GdPtrArray;
+
+GdPtrArray *gd_ptr_array_sized_new(unsigned int size);
+GdPtrArray *gd_ptr_array_new(void);
+void gd_ptr_array_add(GdPtrArray *array, void *data);
+boolean gd_ptr_array_remove(GdPtrArray *array, void *data);
+void gd_ptr_array_free(GdPtrArray *array, boolean free_data);
+#define gd_ptr_array_index(array, index) ((array)->data)[index]
+
+boolean gd_caveset_load_from_bdcff(const char *contents);
+GdPtrArray *gd_caveset_save_to_bdcff(void);
+
+#endif // BD_BDCFF_H
diff --git a/src/game_bd/bd_c64import.c b/src/game_bd/bd_c64import.c
new file mode 100644 (file)
index 0000000..b3e0310
--- /dev/null
@@ -0,0 +1,2643 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+// make all caves selectable.
+static boolean gd_import_as_all_caves_selectable = TRUE;
+
+// conversion table for imported bd1 caves.
+static const GdElement bd1_import_table[] =
+{
+  /*  0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
+  /*  4 */ O_PRE_OUTBOX, O_OUTBOX, O_STEEL_EXPLODABLE, O_STEEL,
+  /*  8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /*  c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
+  /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
+  // ----- ACID: marek roth extension in crazy dream 3
+  /* 18 */ O_ACID, O_ACID, O_EXPLODE_1, O_EXPLODE_2,
+  /* 1c */ O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5, O_PRE_DIA_1,
+  /* 20 */ O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4, O_PRE_DIA_5,
+  /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
+  /* 28 */ O_PRE_PL_3, O_PRE_PL_3, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL,
+  /* 2c */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* 30 */ O_BUTTER_4, O_BUTTER_1, O_BUTTER_2, O_BUTTER_3,
+  /* 34 */ O_BUTTER_4, O_BUTTER_1, O_BUTTER_2, O_BUTTER_3,
+  /* 38 */ O_PLAYER, O_PLAYER, O_AMOEBA, O_AMOEBA,
+  /* 3c */ O_VOODOO, O_INVIS_OUTBOX, O_SLIME, O_UNKNOWN
+};
+
+// conversion table for imported plck caves.
+static const GdElement plck_import_nybble[] =
+{
+  /*  0 */ O_STONE, O_DIAMOND, O_MAGIC_WALL, O_BRICK,
+  /*  4 */ O_STEEL, O_H_EXPANDING_WALL, O_VOODOO, O_DIRT,
+  /*  8 */ O_FIREFLY_1, O_BUTTER_4, O_AMOEBA, O_SLIME,
+  /* 12 */ O_PRE_INVIS_OUTBOX, O_PRE_OUTBOX, O_INBOX, O_SPACE
+};
+
+// conversion table for imported 1stb caves.
+static const GdElement firstboulder_import_table[] =
+{
+  /*  0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
+  /*  4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
+  /*  8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /*  c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
+  /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
+  /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
+  /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1,
+  /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
+  /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
+  // ----- CLOCK: not mentioned in marek's bd inside faq
+  /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL,
+  /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
+  /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
+  /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
+  /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
+  /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
+  /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
+  /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
+  /* 48 */ O_BLADDER_8, O_BLADDER_8, O_EXPLODE_1, O_EXPLODE_1,
+  /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
+  /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
+  /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
+  /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
+  /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
+  /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
+  /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
+  /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
+  /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
+  /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
+  /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
+  /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
+  /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
+};
+
+// conversion table for imported crazy dream caves.
+static const GdElement crazydream_import_table[] =
+{
+  /*  0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
+  /*  4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
+  /*  8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /*  c */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /* 10 */ O_STONE, O_STONE, O_STONE_F, O_STONE_F,
+  /* 14 */ O_DIAMOND, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_F,
+  /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
+  /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1,
+  // ----- 6 different stages
+  /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
+  /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
+  // ----- CLOCK: not mentioned in marek's bd inside faq
+  /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL,
+  /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
+  /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
+  /* 34 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
+  /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
+  /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
+  /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
+  /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
+  /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
+  /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
+  /* 50 */ O_PLAYER, O_PLAYER, O_PLAYER_BOMB, O_PLAYER_BOMB,
+  /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED, O_VOODOO, O_AMOEBA,
+  /* 58 */ O_AMOEBA, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
+  /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
+  /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
+  /* 64 */ O_GHOST, O_GHOST, O_GHOST_EXPL_1, O_GHOST_EXPL_2,
+  /* 68 */ O_GHOST_EXPL_3, O_GHOST_EXPL_4, O_GRAVESTONE, O_STONE_GLUED,
+  /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
+  /* 70 */ O_WAITING_STONE, O_WAITING_STONE, O_CHASING_STONE, O_CHASING_STONE,
+  /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
+  /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
+  /* 7c */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
+
+  /* 80 */ O_POT, O_PLAYER_STIRRING, O_GRAVITY_SWITCH, O_GRAVITY_SWITCH,
+  /* 84 */ O_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, O_BOX, O_BOX,
+  /* 88 */ O_UNKNOWN, O_UNKNOWN, O_ACID, O_ACID,
+  /* 8c */ O_KEY_1, O_KEY_2, O_KEY_3, O_UNKNOWN,
+  /* 90 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* 94 */ O_UNKNOWN, O_TELEPORTER, O_UNKNOWN, O_SKELETON,
+  /* 98 */ O_WATER, O_WATER_16, O_WATER_15, O_WATER_14,
+  /* 9c */ O_WATER_13, O_WATER_12, O_WATER_11, O_WATER_10,
+  /* a0 */ O_WATER_9, O_WATER_8, O_WATER_7, O_WATER_6,
+  /* a4 */ O_WATER_5, O_WATER_4, O_WATER_3, O_WATER_2,
+  /* a8 */ O_WATER_1, O_COW_ENCLOSED_1, O_COW_ENCLOSED_2, O_COW_ENCLOSED_3,
+  /* ac */ O_COW_ENCLOSED_4, O_COW_ENCLOSED_5, O_COW_ENCLOSED_6, O_COW_ENCLOSED_7,
+  /* b0 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
+  /* b4 */ O_COW_1, O_COW_2, O_COW_3, O_COW_4,
+  /* b8 */ O_DIRT_GLUED, O_STEEL_EXPLODABLE, O_DOOR_1, O_DOOR_2,
+  /* bc */ O_DOOR_3, O_FALLING_WALL, O_FALLING_WALL_F, O_FALLING_WALL_F,
+  /* c0 */ O_WALLED_DIAMOND, O_UNKNOWN, O_WALLED_KEY_1, O_WALLED_KEY_2,
+  /* c5 = brick?! (vital key), c7 = dirt?! (think twice) */
+  /* c7 = dirt, as it has a code which will change it to dirt. */
+  /* c4 */ O_WALLED_KEY_3, O_BRICK, O_UNKNOWN, O_DIRT,
+  /* c8 */ O_DIRT2, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* cc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* d0 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* d4 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* d8 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* dc */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  /* e0 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
+  /* e4 */ O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4,
+  /* e8 */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
+  /* ec */ O_ALT_BUTTER_3, O_ALT_BUTTER_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2,
+  /* f0 */ O_WATER, O_WATER, O_WATER, O_WATER,
+  /* f4 */ O_WATER, O_WATER, O_WATER, O_WATER,
+  /* f8 */ O_WATER, O_WATER, O_WATER, O_WATER,
+  /* fc */ O_WATER, O_WATER, O_WATER, O_WATER,
+};
+
+// conversion table for imported 1stb caves.
+const GdElement gd_crazylight_import_table[] =
+{
+  /*  0 */ O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL,
+  /*  4 */ O_PRE_OUTBOX, O_OUTBOX, O_PRE_INVIS_OUTBOX, O_INVIS_OUTBOX,
+  /*  8 */ O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  /*  c */ O_FIREFLY_1|SCANNED, O_FIREFLY_2|SCANNED, O_FIREFLY_3|SCANNED, O_FIREFLY_4|SCANNED,
+  /* 10 */ O_STONE, O_STONE|SCANNED, O_STONE_F, O_STONE_F|SCANNED,
+  /* 14 */ O_DIAMOND, O_DIAMOND|SCANNED, O_DIAMOND_F, O_DIAMOND_F|SCANNED,
+  /* 18 */ O_PRE_CLOCK_1, O_PRE_CLOCK_2, O_PRE_CLOCK_3, O_PRE_CLOCK_4,
+  /* 1c */ O_BITER_SWITCH, O_BITER_SWITCH, O_BLADDER_SPENDER, O_PRE_DIA_1,
+  // ----- 6 different stages, the first is the pre_dia_0
+  /* 20 */ O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4,
+  /* 24 */ O_PRE_DIA_5, O_INBOX, O_PRE_PL_1, O_PRE_PL_2,
+  // ----- CLOCK: not mentioned in marek's bd inside faq
+  /* 28 */ O_PRE_PL_3, O_CLOCK, O_H_EXPANDING_WALL, O_H_EXPANDING_WALL|SCANNED,
+  /* 2c */ O_CREATURE_SWITCH, O_CREATURE_SWITCH, O_EXPANDING_WALL_SWITCH, O_EXPANDING_WALL_SWITCH,
+  /* 30 */ O_BUTTER_3, O_BUTTER_4, O_BUTTER_1, O_BUTTER_2,
+  /* 34 */ O_BUTTER_3|SCANNED, O_BUTTER_4|SCANNED, O_BUTTER_1|SCANNED, O_BUTTER_2|SCANNED,
+  /* 38 */ O_STEEL, O_SLIME, O_BOMB, O_SWEET,
+  /* 3c */ O_PRE_STONE_1, O_PRE_STONE_2, O_PRE_STONE_3, O_PRE_STONE_4,
+  /* 40 */ O_BLADDER, O_BLADDER_1, O_BLADDER_2, O_BLADDER_3,
+  /* 44 */ O_BLADDER_4, O_BLADDER_5, O_BLADDER_6, O_BLADDER_7,
+  /* 48 */ O_BLADDER_8, O_BLADDER_8|SCANNED, O_EXPLODE_1, O_EXPLODE_1,
+  /* 4c */ O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5,
+  /* 50 */ O_PLAYER, O_PLAYER|SCANNED, O_PLAYER_BOMB, O_PLAYER_BOMB|SCANNED,
+  /* 54 */ O_PLAYER_GLUED, O_PLAYER_GLUED|SCANNED, O_VOODOO, O_AMOEBA,
+  /* 58 */ O_AMOEBA|SCANNED, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3,
+  /* 5c */ O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
+  /* 60 */ O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4,
+  /* 64 */ O_ACID, O_ACID, O_FALLING_WALL, O_FALLING_WALL_F,
+  /* 68 */ O_FALLING_WALL_F|SCANNED, O_BOX, O_GRAVESTONE, O_STONE_GLUED,
+  /* 6c */ O_DIAMOND_GLUED, O_DIAMOND_KEY, O_TRAPPED_DIAMOND, O_GRAVESTONE,
+  /* 70 */ O_WAITING_STONE, O_WAITING_STONE|SCANNED, O_CHASING_STONE, O_CHASING_STONE|SCANNED,
+  /* 74 */ O_PRE_STEEL_1, O_PRE_STEEL_2, O_PRE_STEEL_3, O_PRE_STEEL_4,
+  /* 78 */ O_BITER_1, O_BITER_2, O_BITER_3, O_BITER_4,
+  /* 7c */ O_BITER_1|SCANNED, O_BITER_2|SCANNED, O_BITER_3|SCANNED, O_BITER_4|SCANNED,
+};
+
+GdPropertyDefault gd_defaults_bd1[] =
+{
+  { CAVE_OFFSET(level_amoeba_threshold), 200 },
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), TRUE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(diagonal_movements), FALSE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), FALSE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), FALSE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_backwards), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_time), 0 },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), TRUE },
+  { CAVE_OFFSET(intermission_rewardlife), FALSE },
+  { CAVE_OFFSET(magic_wall_stops_amoeba), TRUE },
+  { CAVE_OFFSET(magic_wall_breakscan), TRUE },
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), FALSE },
+  { CAVE_OFFSET(short_explosions), TRUE },
+  { CAVE_OFFSET(slime_predictable), TRUE },
+  { CAVE_OFFSET(snap_element), O_SPACE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_BD1 },
+  { CAVE_OFFSET(pal_timing), TRUE },
+
+  { -1 },
+};
+
+GdPropertyDefault gd_defaults_bd2[] =
+{
+  { CAVE_OFFSET(level_amoeba_threshold), 200 },
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), FALSE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(diagonal_movements), FALSE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), FALSE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), FALSE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_backwards), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_time), 0 },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), TRUE },
+  { CAVE_OFFSET(intermission_rewardlife), FALSE },
+  { CAVE_OFFSET(magic_wall_stops_amoeba), FALSE },    // marek roth bd inside faq 3.0
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), FALSE },
+  { CAVE_OFFSET(short_explosions), TRUE },
+  { CAVE_OFFSET(slime_predictable), TRUE },
+  { CAVE_OFFSET(snap_element), O_SPACE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(pal_timing), TRUE },
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_BD2 },
+
+  { -1 },
+};
+
+GdPropertyDefault gd_defaults_plck[] =
+{
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), FALSE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(border_scan_first_and_last), FALSE },
+  { CAVE_OFFSET(diagonal_movements), FALSE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), FALSE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), FALSE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_backwards), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_time), 0 },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), TRUE },
+  { CAVE_OFFSET(intermission_rewardlife), FALSE },
+  { CAVE_OFFSET(magic_wall_stops_amoeba), FALSE },
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), FALSE },
+  { CAVE_OFFSET(short_explosions), TRUE },
+  { CAVE_OFFSET(snap_element), O_SPACE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(pal_timing), TRUE },
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK },
+
+  { -1 },
+};
+
+GdPropertyDefault gd_defaults_1stb[] =
+{
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), FALSE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), TRUE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), TRUE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), TRUE },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), FALSE },
+  { CAVE_OFFSET(intermission_rewardlife), TRUE },
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), TRUE },
+  { CAVE_OFFSET(short_explosions), FALSE },
+  { CAVE_OFFSET(slime_predictable), TRUE },
+  { CAVE_OFFSET(snap_element), O_SPACE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(pal_timing), TRUE },
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK },
+  // not immediately to diamond, but with animation
+  { CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1 },
+  { CAVE_OFFSET(dirt_looks_like), O_DIRT2 },
+
+  { -1 },
+};
+
+GdPropertyDefault gd_defaults_crdr_7[] =
+{
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), FALSE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), TRUE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), TRUE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), FALSE },
+  { CAVE_OFFSET(intermission_rewardlife), TRUE },
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), FALSE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), TRUE },
+  { CAVE_OFFSET(short_explosions), FALSE },
+  { CAVE_OFFSET(slime_predictable), TRUE },
+  { CAVE_OFFSET(snap_element), O_SPACE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(pal_timing), TRUE },
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_CRDR },
+  // not immediately to diamond, but with animation
+  { CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1 },
+  { CAVE_OFFSET(water_does_not_flow_down), TRUE },
+  // in crdr, skeletons can also be used to open the gate
+  { CAVE_OFFSET(skeletons_worth_diamonds), 1 },
+  // the intermission "survive" needs this flag
+  { CAVE_OFFSET(gravity_affects_all), FALSE },
+
+  { -1 },
+};
+
+GdPropertyDefault gd_defaults_crli[] =
+{
+  { CAVE_OFFSET(amoeba_growth_prob), 31250 },
+  { CAVE_OFFSET(amoeba_fast_growth_prob), 250000 },
+  { CAVE_OFFSET(amoeba_timer_started_immediately), FALSE },
+  { CAVE_OFFSET(amoeba_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(lineshift), TRUE },
+  { CAVE_OFFSET(wraparound_objects), TRUE },
+  { CAVE_OFFSET(voodoo_collects_diamonds), TRUE },
+  { CAVE_OFFSET(voodoo_dies_by_stone), TRUE },
+  { CAVE_OFFSET(voodoo_disappear_in_explosion), FALSE },
+  { CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE },
+  { CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE },
+  { CAVE_OFFSET(level_hatching_delay_time[0]), 2 },
+  { CAVE_OFFSET(intermission_instantlife), FALSE },
+  { CAVE_OFFSET(intermission_rewardlife), TRUE },
+  { CAVE_OFFSET(magic_timer_zero_is_infinite), FALSE },
+  { CAVE_OFFSET(magic_timer_wait_for_hatching), TRUE },
+  { CAVE_OFFSET(pushing_stone_prob), 250000 },
+  { CAVE_OFFSET(pushing_stone_prob_sweet), 1000000 },
+  { CAVE_OFFSET(active_is_first_found), TRUE },
+  { CAVE_OFFSET(short_explosions), FALSE },
+  { CAVE_OFFSET(slime_predictable), TRUE },
+  { CAVE_OFFSET(max_time), 999 },
+
+  { CAVE_OFFSET(pal_timing), TRUE },
+  { CAVE_OFFSET(scheduling), GD_SCHEDULING_PLCK },
+  // not immediately to diamond, but with animation
+  { CAVE_OFFSET(amoeba_enclosed_effect), O_PRE_DIA_1 },
+
+  { -1 },
+};
+
+
+// internal character (letter) codes in c64 games.
+// missing: "triple line" after >, diamond between ()s, player's head after )
+// used for converting names of caves imported from crli and other types of binary data
+const char gd_bd_internal_chars[] =
+  "            ,!./0123456789:*<=>  ABCDEFGHIJKLMNOPQRSTUVWXYZ( ) _";
+
+// used for bdcff engine flag.
+const char *gd_engines[] =
+{
+  "BD1",
+  "BD2",
+  "PLCK",
+  "1stB",
+  "CrDr",
+  "CrLi"
+};
+
+// to convert predictable slime values to bit masks
+static int slime_shift_msb(int c64_data)
+{
+  int i, perm;
+
+  perm = 0;
+
+  for (i = 0; i < c64_data; i++)
+    // shift in this many msb 1's
+    perm = (0x100|perm) >> 1;
+
+  return perm;
+}
+
+static GdElement bd1_import(byte c, int i)
+{
+  if (c < ARRAY_SIZE(bd1_import_table))
+    return bd1_import_table[c];
+
+  Warn("Invalid BD1 element in imported file at cave data %d: %d", i, c);
+
+  return O_UNKNOWN;
+}
+
+// deluxe caves 1 contained a special element, non-sloped brick.
+static GdElement deluxecaves_1_import(byte c, int i)
+{
+  GdElement e = bd1_import(c, i);
+
+  if (e == O_H_EXPANDING_WALL)
+    e = O_BRICK_NON_SLOPED;
+
+  return e;
+}
+
+static GdElement firstboulder_import(byte c, int i)
+{
+  if (c < ARRAY_SIZE(firstboulder_import_table))
+    return firstboulder_import_table[c];
+
+  Warn("Invalid 1stB element in imported file at cave data %d: %d", i, c);
+
+  return O_UNKNOWN;
+}
+
+static GdElement crazylight_import(byte c, int i)
+{
+  if (c < ARRAY_SIZE(gd_crazylight_import_table))
+    return gd_crazylight_import_table[c] & O_MASK;    // & O_MASK: do not import "scanned" flag
+
+  Warn("Invalid CrLi element in imported file at cave data %d: %d", i, c);
+
+  return O_UNKNOWN;
+}
+
+GdPropertyDefault *gd_get_engine_default_array(GdEngine engine)
+{
+  switch(engine)
+  {
+    case GD_ENGINE_BD1:
+      return gd_defaults_bd1;
+      break;
+
+    case GD_ENGINE_BD2:
+      return gd_defaults_bd2;
+      break;
+
+    case GD_ENGINE_PLCK:
+      return gd_defaults_plck;
+      break;
+
+    case GD_ENGINE_1STB:
+      return gd_defaults_1stb;
+      break;
+
+    case GD_ENGINE_CRDR7:
+      return gd_defaults_crdr_7;
+      break;
+
+    case GD_ENGINE_CRLI:
+      return gd_defaults_crli;
+      break;
+
+      // to avoid compiler warning
+    case GD_ENGINE_INVALID:
+      break;
+  }
+
+  return gd_defaults_bd1;
+}
+
+void gd_cave_set_engine_defaults(GdCave *cave, GdEngine engine)
+{
+  gd_cave_set_defaults_from_array(cave, gd_get_engine_default_array(engine));
+
+  // these have hardcoded ckdelay.
+  // setting this ckdelay array does not fit into the gd_struct_default scheme.
+  if (engine == GD_ENGINE_BD1)
+  {
+    cave->level_ckdelay[0] = 12;
+    cave->level_ckdelay[1] = 6;
+    cave->level_ckdelay[2] = 3;
+    cave->level_ckdelay[3] = 1;
+    cave->level_ckdelay[4] = 0;
+  }
+
+  if (engine == GD_ENGINE_BD2)
+  {
+    cave->level_ckdelay[0] = 9;    // 180ms
+    cave->level_ckdelay[1] = 8;    // 160ms
+    cave->level_ckdelay[2] = 7;    // 140ms
+    cave->level_ckdelay[3] = 6;    // 120ms
+    cave->level_ckdelay[4] = 6;    // 120ms (!) not faster than level4
+  }
+}
+
+GdEngine gd_cave_get_engine_from_string(const char *param)
+{
+  int i;
+
+  for (i = 0; i < GD_ENGINE_INVALID; i++)
+    if (strcasecmp(param, gd_engines[i]) == 0)
+      return (GdEngine)i;
+
+  return GD_ENGINE_INVALID;
+}
+
+// ============================================================================
+//
+// cave import routines.
+// take a cave, data, and maybe remaining bytes.
+// return the number of bytes read, -1 if error.
+//
+// ============================================================================
+
+/*
+  take care of required diamonds values == 0 or > 100.
+  in original bd, the counter was only two-digit. so bd3 cave f
+  says 150 diamonds required, but you only had to collect 50.
+  also, gate opening is triggered by incrementing diamond
+  count and THEN checking if more required; so if required was
+  0, you had to collect 100. (also check crazy light 8 cave "1000")
+
+  http://www.boulder-dash.nl/forum/viewtopic.php?t=88
+*/
+
+// import bd1 cave data into our format.
+static int cave_copy_from_bd1(GdCave *cave, const byte *data, int remaining_bytes,
+                             GdCavefileFormat format)
+{
+  int length, direction;
+  int index;
+  int level;
+  int x1, y1, x2, y2;
+  byte code;
+  GdElement elem;
+  GdElement (* import_func) (byte c, int i);
+  int i;
+
+  // cant be shorted than this: header + no objects + delimiter
+  if (remaining_bytes < 33)
+  {
+    Error("truncated BD1 cave data, %d bytes", remaining_bytes);
+
+    return -1;
+  }
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_BD1);
+
+  if (format == GD_FORMAT_BD1_ATARI)
+    cave->scheduling = GD_SCHEDULING_BD1_ATARI;
+
+  if (format == GD_FORMAT_DC1)
+    import_func = deluxecaves_1_import;
+  else
+    import_func = bd1_import;
+
+  // set visible size for intermission
+  if (cave->intermission)
+  {
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  // cave number data[0]
+  cave->diamond_value = data[2];
+  cave->extra_diamond_value = data[3];
+
+  for (level = 0; level < 5; level++)
+  {
+    cave->level_amoeba_time[level] = data[1];
+
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[level] == 0)
+      cave->level_amoeba_time[level] = 999;
+
+    cave->level_magic_wall_time[level] = data[1];
+    cave->level_rand[level] = data[4 + level];
+    cave->level_diamonds[level] = data[9 + level] % 100;    // check comment above
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here means 100 to collect
+    if (cave->level_diamonds[level] == 0)
+      cave->level_diamonds[level] = 100;
+    cave->level_time[level] = data[14 + level];
+  }
+
+  /*
+    LogicDeLuxe extension: acid
+    $16 Acid speed (unused in the original BD1)
+    $17 Bit 2: if set, Acid's original position converts to explosion puff during spreading.
+    Otherwise, Acid remains intact, ie. it's just growing. (unused in the original BD1)
+    $1C Acid eats this element. (also Probability of element 1)
+
+    there is no problem importing these; as other bd1 caves did not contain acid at all,
+    so it does not matter how we set the values.
+  */
+
+  // 0x1c index: same as probability1 !!!!! don't be surprised. we do a &0x3f because of this
+  cave->acid_eats_this = import_func(data[0x1c] & 0x3F, 0x1c);
+
+  // acid speed, *1e6 as probabilities are stored in int
+  cave->acid_spread_ratio = data[0x16] / 255.0 * 1E6 + 0.5;
+
+  cave->acid_turns_to = (data[0x17] & (1 << 2)) ? O_EXPLODE_3 : O_ACID;
+
+  if (format == GD_FORMAT_BD1_ATARI)
+  {
+    // atari colors
+    cave->color1 = gd_atari_color(data[0x13]);
+    cave->color2 = gd_atari_color(data[0x14]);
+    cave->color3 = gd_atari_color(data[0x15]);
+    cave->color4 = gd_atari_color(data[0x16]);      // in atari, amoeba was green
+    cave->color5 = gd_atari_color(data[0x16]);      // in atari, slime was green
+    cave->colorb = gd_atari_color(data[0x17]);      // border = background
+    cave->color0 = gd_atari_color(data[0x17]);      // background
+  }
+  else
+  {
+    // c64 colors
+    cave->colorb = gd_c64_color(0);                 // border = background, fixed color
+    cave->color0 = gd_c64_color(0);                 // background, fixed color
+    cave->color1 = gd_c64_color(data[0x13] & 0xf);
+    cave->color2 = gd_c64_color(data[0x14] & 0xf);
+    cave->color3 = gd_c64_color(data[0x15] & 0x7);  // lower 3 bits only (vic-ii worked this way)
+    cave->color4 = cave->color3;                    // in bd1, amoeba was color3
+    cave->color5 = cave->color3;                    // no slime, but let it be color 3
+  }
+
+  // random fill
+  for (i = 0; i < 4; i++)
+  {
+    cave->random_fill[i] = import_func(data[24 + i], 24 + i);
+    cave->random_fill_probability[i] = data[28 + i];
+  }
+
+  /*
+   * Decode the explicit cave data
+   */
+  index = 32;
+
+  while (data[index] != 0xFF && index < remaining_bytes && index < 255)
+  {
+    code = data[index];
+
+    // crazy dream 3 extension:
+    if (code == 0x0f)
+    {
+      int x1, y1, nx, ny, dx, dy;
+      int x, y;
+
+      // as this one uses nonstandard dx dy values, create points instead
+      elem = import_func(data[index + 1], index + 1);
+      x1 = data[index + 2];
+      y1 = data[index + 3] - 2;
+      nx = data[index + 4];
+      ny = data[index + 5];
+      dx = data[index + 6];
+      dy = data[index + 7] + 1;
+
+      for (y = 0; y < ny; y++)
+      {
+       for (x = 0; x < nx; x++)
+       {
+         int pos = x1 + y1 * 40 + y * dy * 40 + x * dx;
+
+         cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, pos % 40, pos / 40, elem));
+       }
+      }
+
+      index += 8;
+    }
+    else
+    {
+      // object is code & 3f, object type is upper 2 bits
+      elem = import_func(code & 0x3F, index);
+
+      switch ((code >> 6) & 3)
+      {
+       case 0:                // 00: POINT
+         x1 = data[index + 1];
+         y1 = data[index + 2] - 2;
+
+         if (x1 >= cave->w || y1 >= cave->h)
+           Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
+
+         cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
+
+         index += 3;
+         break;
+
+       case 1:                // 01: LINE
+         x1 = data[index + 1];
+         y1 = data[index + 2] - 2;
+         length = (byte)data[index + 3] - 1;
+         direction = data[index + 4];
+
+         if (length < 0)
+         {
+           Warn("line length negative, not displaying line at all, at byte %d", index);
+         }
+         else
+         {
+           if (direction > GD_MV_UP_LEFT)
+           {
+             Warn("invalid line direction %d at byte %d", direction, index);
+             direction = GD_MV_STILL;
+           }
+
+           x2 = x1 + length * gd_dx[direction + 1];
+           y2 = y1 + length * gd_dy[direction + 1];
+
+           if (x1 >= cave->w ||
+               y1 >= cave->h ||
+               x2 >= cave->w ||
+               y2 >= cave->h)
+             Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+           cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+         }
+
+         index += 5;
+         break;
+
+       case 2:                // 10: FILLED RECTANGLE
+         x1 = data[index + 1];
+         y1 = data[index + 2] - 2;
+         x2 = x1 + data[index + 3] - 1;    // width
+         y2 = y1 + data[index + 4] - 1;    // height
+
+         if (x1 >= cave->w ||
+             y1 >= cave->h ||
+             x2 >= cave->w ||
+             y2 >= cave->h)
+           Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+         cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem, import_func(data[index + 5], index + 5)));
+
+         index += 6;
+         break;
+
+       case 3:                // 11: OPEN RECTANGLE (OUTLINE)
+         x1 = data[index + 1];
+         y1 = data[index + 2] - 2;
+         x2 = x1 + data[index + 3] - 1;
+         y2 = y1 + data[index + 4] - 1;
+
+         if (x1 >= cave->w ||
+             y1 >= cave->h ||
+             x2 >= cave->w ||
+             y2 >= cave->h)
+           Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+         cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+
+         index += 5;
+         break;
+      }
+    }
+  }
+
+  if (data[index] != 0xFF)
+  {
+    Error("import error, cave not delimited with 0xFF");
+    return -1;
+  }
+
+  return index + 1;
+}
+
+// import bd2 cave data into our format. return number of bytes if pointer passed.
+// this is pretty much the same as above, only the encoding was different.
+static int cave_copy_from_bd2(GdCave *cave, const byte *data, int remaining_bytes,
+                             GdCavefileFormat format)
+{
+  int index;
+  int i;
+  int x, y, rx, ry;
+  int x1, y1, x2, y2, dx, dy;
+  GdElement elem;
+
+  if (remaining_bytes < 0x1A + 5)
+  {
+    Error("truncated BD2 cave data, %d bytes", remaining_bytes);
+    return -1;
+  }
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_BD2);
+
+  if (format == GD_FORMAT_BD2_ATARI)
+    cave->scheduling = GD_SCHEDULING_BD2_PLCK_ATARI;
+
+  // set visible size for intermission
+  if (cave->intermission)
+  {
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  cave->diamond_value = data[1];
+  cave->extra_diamond_value = data[2];
+
+  for (i = 0; i < 5; i++)
+  {
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    cave->level_amoeba_time[i] = data[0] == 0 ? 999 : data[0];
+    cave->level_rand[i] = data[13 + i];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed
+    cave->level_diamonds[i] = data[8 + i] == 0 ? 1000 : data[8 + i];
+    cave->level_time[i] = data[3 + i];
+    cave->level_magic_wall_time[i] = data[0];
+  }
+
+  for (i = 0; i < 4; i++)
+  {
+    cave->random_fill[i] = bd1_import(data[0x16 + i], 0x16 + i);
+    cave->random_fill_probability[i] = data[0x12 + i];
+  }
+
+  /*
+   * Decode the explicit cave data
+   */
+  index = 0x1A;
+
+  while (data[index] != 0xFF && index < remaining_bytes)
+  {
+    int nx, ny;
+    unsigned int addr;
+    int val, n, bytes;
+    int length, direction;
+
+    switch (data[index])
+    {
+      case 0:                // LINE
+       elem = bd1_import(data[index + 1], index + 1);
+       y1 = data[index + 2];
+       x1 = data[index + 3];
+
+       // they are multiplied by two - 0 is up, 2 is upright, 4 is right...
+       direction = data[index + 4] / 2;
+       length = data[index + 5] - 1;
+
+       if (direction > GD_MV_UP_LEFT)
+       {
+         Warn("invalid line direction %d at byte %d", direction, index);
+         direction = GD_MV_STILL;
+       }
+
+       x2 = x1 + length * gd_dx[direction + 1];
+       y2 = y1 + length * gd_dy[direction + 1];
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+
+       index += 6;
+       break;
+
+      case 1:                // OPEN RECTANGLE
+       elem = bd1_import(data[index + 1], index + 1);
+       y1 = data[index + 2];
+       x1 = data[index + 3];
+       y2 = y1 + data[index + 4] - 1;    // height
+       x2 = x1 + data[index + 5] - 1;
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+
+       index += 6;
+       break;
+
+      case 2:                // FILLED RECTANGLE
+       elem = bd1_import(data[index + 1], index + 1);
+       y1 = data[index + 2];
+       x1 = data[index + 3];
+       y2 = y1 + data[index + 4] - 1;
+       x2 = x1 + data[index + 5] - 1;
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem, bd1_import(data[index+6], index+6)));
+
+       index += 7;
+       break;
+
+      case 3:                // POINT
+       elem = bd1_import(data[index + 1], index + 1);
+       y1 = data[index + 2];
+       x1 = data[index + 3];
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h)
+         Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
+
+       index += 4;
+       break;
+
+      case 4:                // RASTER
+       elem = bd1_import(data[index + 1], index + 1);
+       y1 = data[index + 2];     // starting pos
+       x1 = data[index + 3];
+       ny = data[index + 4] - 1; // number of elements
+       nx = data[index + 5] - 1;
+       dy = data[index + 6];     // displacement
+       dx = data[index + 7];
+       y2 = y1 + dy * ny;        // calculate rectangle
+       x2 = x1 + dx * nx;
+
+       // guess this has to be here, after x2,y2 calculation, because of some bugs in imported data
+       if (dy < 1)
+         dy = 1;
+       if (dx < 1)
+         dx = 1;
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
+
+       index += 8;
+       break;
+
+      case 5:
+       // profi boulder extension: bitmap
+       elem = bd1_import(data[index + 1], index + 1);
+       bytes = data[index + 2];    // number of bytes in bitmap
+
+       if (bytes >= cave->w * cave->h / 8)
+         Warn("invalid bitmap length at byte %d", index - 4);
+
+       addr = 0;
+       addr += data[index + 3];         // msb
+       addr += data[index + 4] << 8;    // lsb
+
+       // this was a pointer to the cave work memory (used during game).
+       addr -= 0x0850;
+
+       if (addr >= cave->w * cave->h)
+         Warn("invalid bitmap start address at byte %d", index - 4);
+
+       x1 = addr % 40;
+       y1 = addr / 40;
+
+       for (i = 0; i < bytes; i++)
+       {
+         // for ("bytes" number of bytes)
+         val = data[index + 5 + i];
+
+         for (n = 0; n < 8; n++)
+         {
+           // for (8 bits in a byte)
+           if ((val & 1) != 0) // convert to single points...
+             cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
+
+           val >>= 1;
+           x1++;   // next cave pos
+
+           if (x1 >= cave->w)
+           {
+             // maybe next line in map
+             x1 = 0;
+             y1++;
+           }
+         }
+       }
+
+       index += 5 + bytes;    // 5 description bytes and "bytes" data bytes
+       break;
+
+      case 6:                // JOIN
+       dy = data[index + 3] / 40;
+       dx = data[index + 3] % 40;    // same byte!!!
+       cave->objects = list_append(cave->objects, gd_object_new_join(GD_OBJECT_LEVEL_ALL, dx, dy, bd1_import(data[index+1], index+1), bd1_import(data[index+2], index+2)));
+
+       index += 4;
+       break;
+
+      case 7:             // SLIME PERMEABILITY
+       // interesting this is set here, and not in the cave header
+       for (i = 0; i < 5; i++)
+         cave->level_slime_permeability_c64[i] = data[index + 1];
+
+       index += 2;
+       break;
+
+      case 9:
+       // profi boulder extension by player: plck-like cave map. the import
+       // routine (any2gdash) inserts it here.
+       if (cave->map != NULL)
+       {
+         Error("contains more than one PLCK map");
+         gd_cave_map_free(cave->map);
+       }
+
+       cave->map = gd_cave_map_new(cave, GdElement);
+
+       for (x = 0; x < cave->w; x++)
+       {
+         // fill the first and the last row with steel wall.
+         cave->map[0][x] = O_STEEL;
+         cave->map[cave->h - 1][x] = O_STEEL;
+       }
+
+       n = 0;    // number of bytes read from map
+
+       // the first and the last rows are not stored.
+       for (y = 1; y < cave->h - 1; y++)
+       {
+         for (x = 0; x < cave->w; x += 2)
+         {
+           cave->map[y][x]     = plck_import_nybble[data[index + 3 + n] >> 4];    // msb 4 bits
+           cave->map[y][x + 1] = plck_import_nybble[data[index + 3 + n] % 16];    // lsb 4 bits
+           n++;
+         }
+       }
+
+       // the position of inbox is stored. this is to check the cave
+       ry = data[index + 1] - 2;
+       rx = data[index + 2];
+
+       // at the start of the cave, bd scrolled to the last player placed during the drawing
+       // (setup) of the cave.
+       // i think this is why a map also stored the coordinates of the player - we can use
+       // this to check its integrity
+       if (rx >= cave->w || ry < 0 ||
+           ry >= cave->h || cave->map[ry][rx] != O_INBOX)
+         Warn ("embedded PLCK map may be corrupted, player coordinates %d,%d", rx, rx);
+
+       index += 3 + n;
+       break;
+
+      default:
+       Warn ("unknown bd2 extension no. %02x at byte %d", data[index], index);
+
+       index += 1;    // skip that byte
+    }
+  }
+
+  if (data[index] != 0xFF)
+  {
+    Error("import error, cave not delimited with 0xFF");
+    return -1;
+  }
+
+  // skip delimiter
+  index++;
+
+  // animation byte - told the engine which objects to animate - to make game faster
+  index++;
+
+  // the colors from the memory dump are appended here by any2gdash
+  if (format == GD_FORMAT_BD2)
+  {
+    // c64 colors
+    cave->color0 = gd_c64_color(0);
+    cave->color1 = gd_c64_color(data[index + 0] & 0xf);
+    cave->color2 = gd_c64_color(data[index + 1] & 0xf);
+    cave->color3 = gd_c64_color(data[index + 2] & 0x7); // lower 3 bits only!
+    cave->color4 = cave->color1;                        // in bd2, amoeba was color1
+    cave->color5 = cave->color1;                        // slime too
+    index += 3;
+  }
+  else
+  {
+    // atari colors
+    cave->color1 = gd_atari_color(data[index + 0]);
+    cave->color2 = gd_atari_color(data[index + 1]);
+    cave->color3 = gd_atari_color(data[index + 2]);
+    cave->color4 = gd_atari_color(data[index + 3]);     // amoeba and slime
+    cave->color5 = gd_atari_color(data[index + 3]);
+    cave->colorb = gd_atari_color(data[index + 4]);     // background and border
+    cave->color0 = gd_atari_color(data[index + 4]);
+    index += 5;
+  }
+
+  return index;
+}
+
+// import plck cave data into our format.
+// length is always 512 bytes, and contains if it is an intermission cave.
+static int cave_copy_from_plck(GdCave *cave, const byte *data,
+                              int remaining_bytes, GdCavefileFormat format)
+{
+  // i don't really think that all this table is needed, but included to be complete.
+  // this is for the dirt and expanding wall looks like effect.
+  // it also contains the individual frames
+  static GdElement plck_graphic_table[] =
+  {
+    /* 3000 */ O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+    /* 3100 */ O_BUTTER_1, O_MAGIC_WALL, O_PRE_DIA_1, O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4, O_PRE_DIA_5, O_OUTBOX_CLOSED,
+    /* 3200 */ O_AMOEBA, O_VOODOO, O_STONE, O_DIRT, O_DIAMOND, O_STEEL, O_PLAYER, O_BRICK,
+    /* 3300 */ O_SPACE, O_OUTBOX_OPEN, O_FIREFLY_1, O_EXPLODE_1, O_EXPLODE_2, O_EXPLODE_3, O_MAGIC_WALL, O_MAGIC_WALL,
+    /* 3400 */ O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK, O_PLAYER_TAP_BLINK,
+    /* 3500 */ O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT, O_PLAYER_LEFT,
+    /* 3600 */ O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT, O_PLAYER_RIGHT,
+    /* 3700 */ O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1, O_BUTTER_1,
+    /* 3800 */ O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA, O_AMOEBA,
+  };
+
+  int i;
+  int x, y;
+
+  if (remaining_bytes < 512)
+  {
+    Error("truncated plck cave data!");
+    return -1;
+  }
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK);
+
+  if (format == GD_FORMAT_PLC_ATARI)
+    cave->scheduling = GD_SCHEDULING_BD2_PLCK_ATARI;
+
+  cave->intermission = data[0x1da] != 0;
+
+  if (cave->intermission)
+  {
+    // set visible size for intermission
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  // cave selection table, was not part of cave data, rather given in game packers.
+  // if a new enough version of any2gdash is used, it will put information after the cave.
+  // detect this here and act accordingly
+  if ((data[0x1f0] == data[0x1f1] - 1) &&
+      (data[0x1f0] == 0x19 ||
+       data[0x1f0] == 0x0e))
+  {
+    int j;
+
+    // found selection table
+    cave->selectable = data[0x1f0] == 0x19;
+    gd_strcpy(cave->name, "              ");
+
+    for (j = 0; j < 12; j++)
+      cave->name[j] = data[0x1f2 + j];
+
+    chompString(cave->name);    // remove spaces
+  }
+  else
+  {
+    // no selection info found, let intermissions be unselectable
+    cave->selectable = !cave->intermission;
+  }
+
+  cave->diamond_value = data[0x1be];
+  cave->extra_diamond_value = data[0x1c0];
+
+  for (i = 0; i < 5; i++)
+  {
+    // plck doesnot really have levels, so just duplicate data five times
+    cave->level_amoeba_time[i] = data[0x1c4];
+
+    // immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[i] == 0)
+      cave->level_amoeba_time[i] = 999;
+
+    cave->level_time[i] = data[0x1ba];
+    cave->level_diamonds[i] = data[0x1bc];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed
+    if (cave->level_diamonds[i] == 0)
+      cave->level_diamonds[i] = 1000;
+
+    cave->level_ckdelay[i] = data[0x1b8];
+    cave->level_magic_wall_time[i] = data[0x1c6];
+    cave->level_slime_permeability_c64[i] = slime_shift_msb(data[0x1c2]);
+  }
+
+  if (format == GD_FORMAT_PLC_ATARI)
+  {
+    // use atari colors
+    cave->colorb = gd_atari_color(0);               // border
+    // indexes in data are not the same order as on c64!!!
+    cave->color0 = gd_atari_color(data[0x1e3]);     // background
+    cave->color1 = gd_atari_color(data[0x1db]);
+    cave->color2 = gd_atari_color(data[0x1dd]);
+    cave->color3 = gd_atari_color(data[0x1df]);
+    // in atari plck, slime and amoeba could not coexist in the same cave.
+    // if amoeba was used, the graphics turned to green, and data at 0x1e1 was set to 0xd4.
+    // if slime was used, graphics to blue, and data at 0x1e1 was set to 0x72.
+    // these two colors could not be changed in the editor at all.
+    // (maybe they could have been changed in a hex editor)
+    cave->color4 = gd_atari_color(data[0x1e1]);
+    cave->color5 = gd_atari_color(data[0x1e1]);
+  }
+  else
+  {
+    // use c64 colors
+    cave->colorb = gd_c64_color(data[0x1db] & 0xf); // border
+    cave->color0 = gd_c64_color(data[0x1dd] & 0xf);
+    cave->color1 = gd_c64_color(data[0x1df] & 0xf);
+    cave->color2 = gd_c64_color(data[0x1e1] & 0xf);
+    cave->color3 = gd_c64_color(data[0x1e3] & 0x7); // lower 3 bits only!
+    cave->color4 = cave->color3;                    // in plck, amoeba was color3
+    cave->color5 = cave->color3;                    // same for slime
+  }
+
+  // ... the cave is stored like a map.
+  cave->map = gd_cave_map_new(cave, GdElement);
+
+  // cave map looked like this.
+  // two rows of steel wall ($44's), then cave description, 20 bytes (40 nybbles) for each line.
+  // the bottom and top lines were not stored... originally.
+  // some games write to the top line; so we import that, too.
+  // also dlp 155 allowed writing to the bottom line; the first 20 $44-s now store the bottom line.
+  // so the cave is essentially shifted one row down in the file:
+  // cave->map[y][x] = data[... y+1 mod height ][x]
+  for (y = 0; y < cave->h; y++)
+  {
+    for (x = 0; x < cave->w; x += 2)
+    {
+      // msb 4 bits: we do not check index ranges, as >>4 and %16 will result in 0..15
+      cave->map[y][x]     = plck_import_nybble[data[((y + 1) % cave->h) * 20 + x / 2] >> 4];
+
+      // lsb 4 bits
+      cave->map[y][x + 1] = plck_import_nybble[data[((y + 1) % cave->h) * 20 + x / 2] % 16];
+    }
+  }
+
+  // FOR NOW, WE DO NOT IMPORT THE BOTTOM BORDER
+  for (x = 0; x < cave->w; x++)
+    cave->map[cave->h - 1][x] = O_STEEL;
+
+  // check for diego-effects
+  // c64 magic values (byte sequences)  0x20 0x90 0x46, also 0xa9 0x1c 0x85
+  if ((data[0x1e5] == 0x20 && data[0x1e6] == 0x90 && data[0x1e7] == 0x46) ||
+      (data[0x1e5] == 0xa9 && data[0x1e6] == 0x1c && data[0x1e7] == 0x85))
+  {
+    // diego effects enabled.
+    cave->stone_bouncing_effect = bd1_import(data[0x1ea], 0x1ea);
+    cave->diamond_falling_effect = bd1_import(data[0x1eb], 0x1eb);
+
+    // explosions: 0x1e was explosion 5, if this is set to default, we also do not read it,
+    // as in our engine this would cause an O_EXPLODE_5 to stay there.
+    if (data[0x1ec] != 0x1e)
+      cave->explosion_effect = bd1_import(data[0x1ec], 0x1ec);
+
+    /*
+      pointer to element graphic.
+      two bytes/column (one element), that is data[xxx] % 16 / 2.
+      also there are 16bytes/row.
+      that is, 0x44 = stone, upper left character. 0x45 = upper right,
+      0x54 = lower right, 0x55 = lower right.
+      so high nybble must be shifted right twice -> data[xxx]/16*4.
+    */
+    cave->dirt_looks_like           = plck_graphic_table[(data[0x1ed] / 16) * 4 + (data[0x1ed] % 16) / 2];
+    cave->expanding_wall_looks_like = plck_graphic_table[(data[0x1ee] / 16) * 4 + (data[0x1ee] % 16) / 2];
+
+    for (i = 0; i < 5; i++)
+      cave->level_amoeba_threshold[i] = data[0x1ef];
+  }
+
+  return 512;
+}
+
+// no one's delight boulder dash essentially: rle compressed plck maps.
+static int cave_copy_from_dlb(GdCave *cave, const byte *data, int remaining_bytes)
+{
+  byte decomp[512];
+  enum
+  {
+    START,        // initial state
+    SEPARATOR,    // got a separator
+    RLE,          // after a separator, got the byte to duplicate
+    NORMAL        // normal, copy bytes till separator
+  } state;
+  int pos, cavepos, i, x, y;
+  byte byte, separator;
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_PLCK); // essentially the plck engine
+
+  for (i = 0; i < 5; i++)
+  {
+    // does not really have levels, so just duplicate data five times
+    cave->level_time[i] = data[1];
+    cave->level_diamonds[i] = data[2];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 needed
+    if (cave->level_diamonds[i] == 0)
+      cave->level_diamonds[i] = 1000;
+
+    cave->level_ckdelay[i] = data[0];
+    cave->level_amoeba_time[i] = data[6];
+
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[i] == 0)
+      cave->level_amoeba_time[i] = 999;
+
+    cave->level_magic_wall_time[i] = data[7];
+    cave->level_slime_permeability_c64[i] = slime_shift_msb(data[5]);
+  }
+
+  cave->diamond_value = data[3];
+  cave->extra_diamond_value = data[4];
+
+  // then 5 color bytes follow
+  cave->colorb = gd_c64_color(data[8]  & 0xf);    // border
+  cave->color0 = gd_c64_color(data[9]  & 0xf);
+  cave->color1 = gd_c64_color(data[10] & 0xf);
+  cave->color2 = gd_c64_color(data[11] & 0xf);
+  cave->color3 = gd_c64_color(data[12] & 0x7);    // lower 3 bits only!
+  cave->color4 = cave->color3;                    // in plck, amoeba was color3
+  cave->color5 = cave->color3;                    // same for slime
+
+  // cave map
+  pos = 13;                     // those 13 bytes were the cave values above
+  cavepos = 0;
+  byte = 0;                     // just to get rid of compiler warning
+  separator = 0;                // just to get rid of compiler warning
+
+  // employ a state machine.
+  state = START;
+
+  while (cavepos < 400 && pos < remaining_bytes)
+  {
+    switch (state)
+    {
+      case START:
+       // first byte is a separator. remember it
+       separator = data[pos];
+
+       // after the first separator, no rle data, just copy.
+       state = NORMAL;
+       break;
+
+      case SEPARATOR:
+       // we had a separator. remember this byte, as this will be duplicated (or more)
+       byte = data[pos];
+       state = RLE;
+       break;
+
+      case RLE:
+       // we had the first byte, duplicate this n times.
+       if (data[pos] == 0xff)
+       {
+         // if it is a 0xff, we will have another byte, which is also a length specifier.
+         // and for this one, duplicate only 254 times
+         if (cavepos + 254 > 400)
+         {
+           Error("DLB import error: RLE data overflows buffer");
+           return -1;
+         }
+
+         for (i = 0; i < 254; i++)
+           decomp[cavepos++] = byte;
+       }
+       else
+       {
+         // if not 0xff, duplicate n times and back to copy mode
+         if (cavepos + data[pos] > 400)
+         {
+           Error("DLB import error: RLE data overflows buffer");
+           return -1;
+         }
+
+         for (i = 0; i < data[pos]; i++)
+           decomp[cavepos++] = byte;
+
+         state = NORMAL;
+       }
+       break;
+
+      case NORMAL:
+       // bytes duplicated; now only copy the remaining, till the next separator.
+       if (data[pos] == separator)
+         state = SEPARATOR;
+       else
+         decomp[cavepos++] = data[pos];    // copy this byte and state is still NORMAL
+       break;
+    }
+
+    pos++;
+  }
+
+  if (cavepos != 400)
+  {
+    Error("DLB import error: RLE processing, cave length %d, should be 400", cavepos);
+    return -1;
+  }
+
+  // process uncompressed map
+  cave->map = gd_cave_map_new(cave, GdElement);
+
+  for (x = 0; x < cave->w; x++)
+  {
+    // fill the first and the last row with steel wall.
+    cave->map[0][x] = O_STEEL;
+    cave->map[cave->h - 1][x] = O_STEEL;
+  }
+
+  for (y = 1; y < cave->h - 1; y++)
+  {
+    for (x = 0; x < cave->w; x += 2)
+    {
+      // msb 4 bits
+      cave->map[y][x]     = plck_import_nybble[decomp[((y - 1) * cave->w + x) / 2] >> 4];
+      // lsb 4 bits
+      cave->map[y][x + 1] = plck_import_nybble[decomp[((y - 1) * cave->w + x) / 2] % 16];
+    }
+  }
+
+  // return number of bytes read from buffer
+  return pos;
+}
+
+// import plck cave data into our format.
+static int cave_copy_from_1stb(GdCave *cave, const byte *data, int remaining_bytes)
+{
+  int i;
+  int x, y;
+
+  if (remaining_bytes < 1024)
+  {
+    Error("truncated 1stb cave data!");
+
+    return -1;
+  }
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_1STB);
+
+  // copy name
+  gd_strcpy(cave->name, "              ");
+
+  for (i = 0; i < 14; i++)
+  {
+    int c = data[0x3a0 + i];
+
+    // import cave name; a conversion table is used for each character
+    if (c < 0x40)
+      c = gd_bd_internal_chars[c];
+    else if (c == 0x74)
+      c = ' ';
+    else if (c == 0x76)
+      c = '?';
+    else
+      c = ' ';    // don't know this, so change to space
+
+    if (i > 0)
+      c = tolower(c);
+
+    cave->name[i] = c;
+  }
+
+  chompString(cave->name);
+
+  cave->intermission = data[0x389] != 0;
+
+  // if it is intermission but not scrollable
+  if (cave->intermission && !data[0x38c])
+  {
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  cave->diamond_value = 100 * data[0x379] + 10 * data[0x379 + 1] + data[0x379 + 2];
+  cave->extra_diamond_value = 100 * data[0x376] + 10 * data[0x376 + 1] + data[0x376 + 2];
+
+  for (i = 0; i < 5; i++)
+  {
+    // plck doesnot really have levels, so just duplicate data five times
+    cave->level_time[i] = 100 * data[0x370] + 10 * data[0x370+1] + data[0x370 + 2];
+
+    // same as gate opening after 0 diamonds
+    if (cave->level_time[i] == 0)
+      cave->level_time[i] = 1000;
+
+    cave->level_diamonds[i] = 100 * data[0x373] + 10 * data[0x373 + 1] + data[0x373 + 2];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed
+    if (cave->level_diamonds[i] == 0)
+      cave->level_diamonds[i] = 1000;
+
+    cave->level_ckdelay[i] = data[0x38a];
+    cave->level_amoeba_time[i] = 256 * (int)data[0x37c] + data[0x37d];
+
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[i] == 0)
+      cave->level_amoeba_time[i] = 999;
+
+    cave->level_magic_wall_time[i] = 256 * (int)data[0x37e] + data[0x37f];
+    cave->level_slime_permeability_c64[i] = data[0x38b];
+    cave->level_bonus_time[i] = data[0x392];
+    cave->level_penalty_time[i] = data[0x393];
+    cave->level_amoeba_threshold[i] = 256 * (int)data[0x390] + data[0x390 + 1];
+  }
+
+  // also has no random data...
+
+  cave->colorb = gd_c64_color(data[0x384] & 0xf);    // border
+  cave->color0 = gd_c64_color(data[0x385] & 0xf);
+  cave->color1 = gd_c64_color(data[0x386] & 0xf);
+  cave->color2 = gd_c64_color(data[0x387] & 0xf);
+  cave->color3 = gd_c64_color(data[0x388] & 0x7);     // lower 3 bits only!
+  cave->color4 = cave->color1;
+  cave->color5 = cave->color1;
+
+  cave->amoeba_growth_prob = (4.0 * 1E6 / (data[0x382] + 1)) + 0.5;   // probabilities store *1M
+  if (cave->amoeba_growth_prob > 1000000)
+    cave->amoeba_growth_prob = 1000000;
+
+  cave->amoeba_fast_growth_prob = (4.0 * 1E6 / (data[0x383] + 1)) + 0.5;
+  if (cave->amoeba_fast_growth_prob > 1000000)
+    cave->amoeba_fast_growth_prob = 1000000;
+
+  if (data[0x380] != 0)
+    cave->creatures_direction_auto_change_time = data[0x381];
+  else
+    cave->diagonal_movements = data[0x381] != 0;
+
+  // ... the cave is stored like a map.
+  cave->map = gd_cave_map_new(cave, GdElement);
+  for (y = 0; y < cave->h; y++)
+    for (x = 0; x < cave->w; x++)
+      cave->map[y][x] = firstboulder_import(data[y * 40 + x], y * 40 + x);
+
+  cave->magic_wall_sound = data[0x38d] == 0xf1;
+
+  // 2d was a normal switch, 2e a changed one.
+  cave->creatures_backwards = data[0x38f] == 0x2d;
+
+  // 2e horizontal, 2f vertical.
+  cave->expanding_wall_changed = data[0x38e] == 0x2f;
+
+  cave->biter_delay_frame      = data[0x394];
+  cave->magic_wall_stops_amoeba        = data[0x395] == 0;    // negated!!
+
+  cave->bomb_explosion_effect  = firstboulder_import(data[0x396], 0x396);
+  cave->explosion_effect       = firstboulder_import(data[0x397], 0x397);
+  cave->stone_bouncing_effect  = firstboulder_import(data[0x398], 0x398);
+  cave->diamond_birth_effect   = firstboulder_import(data[0x399], 0x399);
+  cave->magic_diamond_to       = firstboulder_import(data[0x39a], 0x39a);
+
+  cave->bladder_converts_by    = firstboulder_import(data[0x39b], 0x39b);
+  cave->diamond_falling_effect = firstboulder_import(data[0x39c], 0x39c);
+  cave->biter_eat              = firstboulder_import(data[0x39d], 0x39d);
+  cave->slime_eats_1           = firstboulder_import(data[0x39e], 0x39e);
+  cave->slime_converts_1       = firstboulder_import(data[0x39e] + 3, 0x39e);
+  cave->slime_eats_2           = firstboulder_import(data[0x39f], 0x39f);
+  cave->slime_converts_2       = firstboulder_import(data[0x39f] + 3, 0x39f);
+  cave->magic_diamond_to       = firstboulder_import(data[0x39a], 0x39a);
+
+  // length is always 1024 bytes
+  return 1024;
+}
+
+// crazy dream 7
+static int cave_copy_from_crdr_7(GdCave *cave, const byte *data, int remaining_bytes)
+{
+  int i, index;
+  byte checksum;
+
+  // if we have name, convert
+  gd_strcpy(cave->name, "              ");
+
+  for (i = 0; i < 14; i++)
+  {
+    int c = data[i];
+
+    // import cave name; a conversion table is used for each character
+    if (c < 0x40)
+      c = gd_bd_internal_chars[c];
+    else if (c == 0x74)
+      c = ' ';
+    else if (c == 0x76)
+      c = '?';
+    else
+      c = ' ';
+    if (i > 0)
+      c = tolower(c);
+
+    cave->name[i] = c;
+  }
+
+  chompString(cave->name);    // remove trailing and leading spaces
+
+  cave->selectable = data[14] != 0;
+
+  // jump 15 bytes, 14 was the name and 15 selectability
+  data += 15;
+
+  if (memcmp((char *)data + 0x30, "V4\0020", 4) != 0)
+    Warn("unknown crdr version %c%c%c%c", data[0x30], data[0x31], data[0x32], data[0x33]);
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_CRDR7);
+
+  for (i = 0; i < 5; i++)
+  {
+    cave->level_time[i] = (int)data[0x0] * 100 + data[0x1] * 10 + data[0x2];
+
+    // same as gate opening after 0 diamonds
+    if (cave->level_time[i] == 0)
+      cave->level_time[i] = 1000;
+
+    cave->level_diamonds[i] = (int)data[0x3] * 100 + data[0x4] * 10 + data[0x5];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed
+    if (cave->level_diamonds[i] == 0)
+      cave->level_diamonds[i] = 1000;
+
+    cave->level_ckdelay[i] = data[0x1A];
+    cave->level_rand[i] = data[0x40];
+    cave->level_amoeba_time[i] = (int)data[0xC] * 256 + data[0xD];
+
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[i] == 0)
+      cave->level_amoeba_time[i] = 999;
+
+    cave->level_magic_wall_time[i] = (int)data[0xE] * 256 + data[0xF];
+    cave->level_slime_permeability_c64[i] = data[0x1B];
+    cave->level_bonus_time[i] = data[0x22];
+    cave->level_penalty_time[i] = data[0x23];
+    cave->level_bonus_time[i] = data[0x22];
+    cave->level_penalty_time[i] = data[0x23];
+    cave->level_amoeba_threshold[i] = 256 * (int)data[0x20] + data[0x21];
+  }
+
+  cave->extra_diamond_value = (int)data[0x6] * 100 + data[0x7] * 10 + data[0x8];
+  cave->diamond_value       = (int)data[0x9] * 100 + data[0xA] * 10 + data[0xB];
+
+  if (data[0x10])
+    cave->creatures_direction_auto_change_time = data[0x11];
+
+  cave->colorb = gd_c64_color(data[0x14] & 0xf);    // border
+  cave->color0 = gd_c64_color(data[0x15] & 0xf);
+  cave->color1 = gd_c64_color(data[0x16] & 0xf);
+  cave->color2 = gd_c64_color(data[0x17] & 0xf);
+  cave->color3 = gd_c64_color(data[0x18] & 0x7);    // lower 3 bits only!
+  cave->color4 = cave->color3;
+  cave->color5 = cave->color1;
+
+  cave->intermission = data[0x19] != 0;
+
+  // if it is intermission but not scrollable
+  if (cave->intermission && !data[0x1c])
+  {
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  /*
+    AMOEBA in crazy dash 8:
+    jsr $2500      ; generate true random
+    and $94        ; binary and the current "probability"
+    cmp #$04       ; compare to 4
+    bcs out        ; jump out (do not expand) if carry set, ie. result was less than 4.
+
+    prob values can be like num = 3, 7, 15, 31, 63, ... n lsb bits count.
+    0..3>=4?  0..7>=4?  0..15>=4? and similar.
+    this way, probability of growing is 4/(num+1)
+  */
+
+  cave->amoeba_growth_prob = (4.0 * 1E6 / (data[0x12] + 1)) + 0.5;   // probabilities store * 1M
+  if (cave->amoeba_growth_prob > 1000000)
+    cave->amoeba_growth_prob = 1000000;
+
+  cave->amoeba_fast_growth_prob = (4.0 * 1E6 / (data[0x13] + 1)) + 0.5;
+  if (cave->amoeba_fast_growth_prob > 1000000)
+    cave->amoeba_fast_growth_prob = 1000000;
+
+  // expanding wall direction change - 2e horizontal, 2f vertical
+  cave->expanding_wall_changed = data[0x1e] == 0x2f;
+
+  // 2c was a normal switch, 2d a changed one.
+  cave->creatures_backwards    = data[0x1f] == 0x2d;
+  cave->biter_delay_frame      = data[0x24];
+  cave->magic_wall_stops_amoeba        = data[0x25] == 0;    // negated!!
+
+  cave->bomb_explosion_effect  = crazydream_import_table[data[0x26]];
+  cave->explosion_effect       = crazydream_import_table[data[0x27]];
+  cave->stone_bouncing_effect  = crazydream_import_table[data[0x28]];
+  cave->diamond_birth_effect   = crazydream_import_table[data[0x29]];
+  cave->magic_diamond_to       = crazydream_import_table[data[0x2a]];
+
+  cave->bladder_converts_by    = crazydream_import_table[data[0x2b]];
+  cave->diamond_falling_effect = crazydream_import_table[data[0x2c]];
+  cave->biter_eat              = crazydream_import_table[data[0x2d]];
+  cave->slime_eats_1           = crazydream_import_table[data[0x2e]];
+  cave->slime_converts_1       = crazydream_import_table[data[0x2e] + 3];
+  cave->slime_eats_2           = crazydream_import_table[data[0x2f]];
+  cave->slime_converts_2       = crazydream_import_table[data[0x2f] + 3];
+
+  cave->diagonal_movements             = (data[0x34] & 1) != 0;
+  cave->gravity_change_time            = data[0x35];
+  cave->pneumatic_hammer_frame         = data[0x36];
+  cave->hammered_wall_reappear_frame   = data[0x37];
+  cave->hammered_walls_reappear                = data[0x3f] != 0;
+
+  /*
+    acid in crazy dream 8:
+    jsr $2500    ; true random
+    cmp    $03a8    ; compare to ratio
+    bcs out        ; if it was smaller, forget it for now.
+
+    ie. random<=ratio, then acid grows.
+  */
+
+  // 1e6, probabilities are stored as int
+  cave->acid_spread_ratio = data[0x38] / 255.0 * 1E6 + 0.5;
+
+  cave->acid_eats_this = crazydream_import_table[data[0x39]];
+  switch(data[0x3a] & 3)
+  {
+    case 0: cave->gravity = GD_MV_UP; break;
+    case 1: cave->gravity = GD_MV_DOWN; break;
+    case 2: cave->gravity = GD_MV_LEFT; break;
+    case 3: cave->gravity = GD_MV_RIGHT; break;
+  }
+
+  cave->snap_element = ((data[0x3a] & 4) != 0) ? O_EXPLODE_1 : O_SPACE;
+
+  // we do not know the values for these, so do not import
+  //    cave->dirt_looks_like... data[0x3c]
+  //    cave->expanding_wall_looks_like... data[0x3b]
+  for (i = 0; i < 4; i++)
+  {
+    cave->random_fill[i] = crazydream_import_table[data[0x41 + i]];
+    cave->random_fill_probability[i] = data[0x45 + i];
+  }
+
+  data += 0x49;
+  index = 0;
+
+  while (data[index] != 0xff)
+  {
+    GdElement elem;
+    int x1, y1, x2, y2, dx, dy;
+    int nx, ny;
+    int length, direction;
+
+    // for copy&paste; copy&paste are different objects, static = ugly solution :)
+    static int cx1, cy1, cw, ch;
+
+    switch (data[index])
+    {
+      case 1:    // point
+       elem = crazydream_import_table[data[index + 1]];
+       x1 = data[index + 2];
+       y1 = data[index + 3];
+       if (x1 >= cave->w || y1 >= cave->h)
+         Warn("invalid point coordinates %d,%d at byte %d", x1, y1, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
+
+       index += 4;
+       break;
+
+      case 2: // rectangle
+       elem = crazydream_import_table[data[index + 1]];
+       x1 = data[index + 2];
+       y1 = data[index + 3];
+       x2 = x1 + data[index + 4] - 1;
+       y2 = y1 + data[index + 5] - 1;    // height
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+
+       index += 6;
+       break;
+
+      case 3: // fillrect
+       x1 = data[index + 2];
+       y1 = data[index + 3];
+       x2 = x1 + data[index + 4] - 1;
+       y2 = y1 + data[index + 5] - 1;
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid filled rectangle coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       // border and inside of fill is the same element.
+       cave->objects = list_append(cave->objects, gd_object_new_filled_rectangle(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, crazydream_import_table[data[index + 1]], crazydream_import_table[data[index + 1]]));
+
+       index += 6;
+       break;
+
+      case 4: // line
+       elem = crazydream_import_table[data[index + 1]];
+       if (elem == O_UNKNOWN)
+         Warn("unknown element at %d: %x", index + 1, data[index + 1]);
+
+       x1 = data[index + 2];
+       y1 = data[index + 3];
+       length = data[index + 4];
+       direction = data[index + 5];
+       nx = ((signed)direction - 128) % 40;
+       ny = ((signed)direction - 128) / 40;
+       x2 = x1 + (length - 1) * nx;
+       y2 = y1 + (length - 1) * ny;
+
+       // if either is bigger than one, we cannot treat this as a line. create points instead
+       if (ABS(nx) >= 2 || ABS(ny) >= 2)
+       {
+         for (i = 0; i < length; i++)
+         {
+           cave->objects = list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, x1, y1, elem));
+           x1 += nx;
+           y1 += ny;
+         }
+       }
+       else
+       {
+         // this is a normal line, and will be appended. only do the checking here
+         if (x1 >= cave->w ||
+             y1 >= cave->h ||
+             x2 >= cave->w ||
+             y2 >= cave->h)
+           Warn("invalid line coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index - 5);
+
+         cave->objects = list_append(cave->objects, gd_object_new_line(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, elem));
+       }
+
+       index += 6;
+       break;
+
+      case 6: // copy
+       cx1 = data[index + 1];
+       cy1 = data[index + 2];
+       cw = data[index + 3];
+       ch = data[index + 4];
+
+       if (cx1 >= cave->w ||
+           cy1 >= cave->h ||
+           cx1 + cw > cave->w ||
+           cy1 + ch > cave->h)
+         Warn("invalid copy coordinates %d,%d or size %d,%d at byte %d", cx1, cy1, cw, ch, index);
+
+       index += 5;
+       break;
+
+      case 7: // paste
+       x1 = cx1;
+       y1 = cy1;
+
+       // original stored width and height, we store the coordinates of the source area
+       x2 = cx1 + cw - 1;
+       y2 = cy1 + ch - 1;
+       dx = data[index + 1];    // new pos
+       dy = data[index + 2];
+
+       if (dx >= cave->w ||
+           dy >= cave->h ||
+           dx + cw > cave->w ||
+           dy + ch > cave->h)
+         Warn("invalid paste coordinates %d,%d at byte %d", dx, dy, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_copy_paste(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, FALSE, FALSE));
+
+       index += 3;
+       break;
+
+      case 11: // raster
+       elem = crazydream_import_table[data[index + 1]];
+       x1 = data[index + 2];
+       y1 = data[index + 3];
+       dx = data[index + 4];
+       dy = data[index + 5];
+       nx = data[index + 6] - 1;
+       ny = data[index + 7] - 1;
+       x2 = x1 + dx * nx;    // calculate rectangle we use
+       y2 = y1 + dy * ny;
+
+       if (dx < 1)
+         dx = 1;
+       if (dy < 1)
+         dy = 1;
+
+       if (x1 >= cave->w ||
+           y1 >= cave->h ||
+           x2 >= cave->w ||
+           y2 >= cave->h)
+         Warn("invalid raster coordinates %d,%d %d,%d at byte %d", x1, y1, x2, y2, index);
+
+       cave->objects = list_append(cave->objects, gd_object_new_raster(GD_OBJECT_LEVEL_ALL, x1, y1, x2, y2, dx, dy, elem));
+
+       index += 8;
+       break;
+
+      default:
+       Warn ("unknown crdr extension no. %02x at byte %d", data[index], index);
+       index += 1;    // skip that byte
+       break;
+    }
+  }
+
+  index++;    // skip $ff
+
+  // crazy dream 7 hack
+  checksum = 0;
+
+  for (i = 0; i < 0x3b0; i++)
+    checksum = checksum^data[i];
+
+  if (strEqual(cave->name, "Crazy maze") && checksum == 195)
+    cave->skeletons_needed_for_pot = 0;
+
+  return 15 + 0x49 + index;
+}
+
+static void crazy_dream_9_add_specials(GdCave *cave, const byte *buf, const int length)
+{
+  byte checksum;
+  int i;
+
+  // crazy dream 9 hack
+  checksum = 0;
+  for (i = 0; i < length; i++)
+    checksum = checksum^buf[i];
+
+  // check cave name and the checksum. both are hardcoded here
+  if (strEqual(cave->name, "Rockfall") && checksum == 134)
+  {
+    GdElement rand[4] = { O_DIAMOND, O_STONE, O_ACID, O_DIRT };
+    int prob[4] = { 37, 32, 2, 0 };
+    int seeds[5] = { -1, -1, -1, -1, -1 };
+
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 0, 0, 39, 21, seeds,
+                                           O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
+  }
+
+  if (strEqual(cave->name, "Roll dice now!") && checksum == 235)
+  {
+    GdElement rand[4] = { O_STONE, O_BUTTER_3, O_DIRT, O_DIRT };
+    int prob[4] = { 0x18, 0x08, 0, 0 };
+    int seeds[5] = { -1, -1, -1, -1, -1 };
+
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 0, 0, 39, 21, seeds,
+                                           O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
+  }
+
+  if (strEqual(cave->name, "Random maze") && checksum == 24)
+  {
+    int seeds[5] = { -1, -1, -1, -1, -1 };
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_maze(GD_OBJECT_LEVEL_ALL, 1, 4, 35, 20, 1, 1,
+                                    O_NONE, O_DIRT, 50, seeds));
+  }
+
+  if (strEqual(cave->name, "Metamorphosis") && checksum == 53)
+  {
+    int seeds[5] = { -1, -1, -1, -1, -1 };
+    GdElement rand[4] = { O_STONE, O_DIRT, O_DIRT, O_DIRT };
+    int prob[4] = { 0x18, 0, 0, 0 };
+
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_maze(GD_OBJECT_LEVEL_ALL, 4, 1, 38, 19, 1, 3,
+                                    O_NONE, O_BLADDER_SPENDER, 50, seeds));
+
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_random_fill(GD_OBJECT_LEVEL_ALL, 4, 1, 38, 19, seeds,
+                                           O_DIRT, rand, prob, O_BLADDER_SPENDER, FALSE));
+
+    cave->creatures_backwards = TRUE;    // for some reason, this level worked like that
+  }
+
+  if (strEqual(cave->name, "All the way") && checksum == 33)
+  {
+    int seeds[5] = { -1, -1, -1, -1, -1 };
+
+    cave->objects =
+      list_append(cave->objects,
+                 gd_object_new_maze_unicursal(GD_OBJECT_LEVEL_ALL, 1, 1, 35, 19, 1, 1,
+                                              O_BRICK, O_PRE_DIA_1, 50, seeds));
+
+    // a point which "breaks" the unicursal maze, making it one very long path
+    cave->objects =
+      list_append(cave->objects, gd_object_new_point(GD_OBJECT_LEVEL_ALL, 35, 18, O_BRICK));
+  }
+}
+
+// crazy light contruction kit
+static int cave_copy_from_crli(GdCave *cave, const byte *data, int remaining_bytes)
+{
+  byte uncompressed[1024];
+  int datapos, cavepos, i, x, y;
+  boolean cavefile;
+  const char *versions[] = { "V2.2", "V2.6", "V3.0" };
+  enum
+  {
+    none,
+    V2_2,    // XXX whats the difference between 2.2 and 2.6?
+    V2_6,
+    V3_0
+  } version = none;
+  GdElement (*import) (byte c, int i) = NULL;    // import function
+
+  gd_cave_set_engine_defaults(cave, GD_ENGINE_CRLI);
+
+  // detect if this is a cavefile
+  if (data[0] == 0 &&
+      data[1] == 0xc4 &&
+      data[2] == 'D' &&
+      data[3] == 'L' &&
+      data[4] == 'P')
+  {
+    datapos = 5;    // cavefile, skipping 0x00 0xc4 D L P
+    cavefile = TRUE;
+  }
+  else
+  {
+    // converted from snapshot, skip "selectable" and 14byte name
+    datapos = 15;
+    cavefile = FALSE;
+  }
+
+  // if we have name, convert
+  if (!cavefile)
+  {
+    gd_strcpy(cave->name, "              ");
+
+    for (i = 0; i < 14; i++)
+    {
+      int c = data[i + 1];
+
+      // import cave name; a conversion table is used for each character
+      if (c < 0x40)
+       c = gd_bd_internal_chars[c];
+      else if (c == 0x74)
+       c = ' ';
+      else if (c == 0x76)
+       c = '?';
+      else
+       c = ' ';
+
+      if (i > 0)
+       c = tolower(c);
+
+      cave->name[i] = c;
+    }
+
+    chompString(cave->name);    // remove trailing and leading spaces
+  }
+
+  // uncompress rle data
+  cavepos = 0;
+
+  while (cavepos < 0x3b0)
+  {
+    // <- loop until the uncompressed reaches its size
+    if (datapos >= remaining_bytes)
+    {
+      Error("truncated crli cave data");
+      return -1;
+    }
+
+    if (data[datapos] == 0xbf)
+    {
+      // magic value 0xbf is the escape byte
+      if (datapos + 2 >= remaining_bytes)
+      {
+       Error("truncated crli cave data");
+       return -1;
+      }
+
+      if (data[datapos + 2] + datapos >= sizeof(uncompressed))
+      {
+       // we would run out of buffer, this must be some error
+       Error("invalid crli cave data - RLE length value is too big");
+       return -1;
+      }
+
+      // 0xbf, number, byte to dup
+      for (i = 0; i < data[datapos + 2]; i++)
+       uncompressed[cavepos++] = data[datapos + 1];
+
+      datapos += 3;
+    }
+    else
+    {
+      uncompressed[cavepos++] = data[datapos++];
+    }
+  }
+
+  // check crli version
+  for (i = 0; i < ARRAY_SIZE(versions); i++)
+    if (memcmp((char *)uncompressed + 0x3a0, versions[i], 4) == 0)
+      version = i + 1;
+
+  // v3.0 has falling wall and box, and no ghost.
+  import = version >= V3_0 ? crazylight_import : firstboulder_import;
+
+  if (version == none)
+  {
+    Warn("unknown crli version %c%c%c%c", uncompressed[0x3a0], uncompressed[0x3a1], uncompressed[0x3a2], uncompressed[0x3a3]);
+    import = crazylight_import;
+  }
+
+  // process map
+  cave->map = gd_cave_map_new(cave, GdElement);
+
+  for (y = 0; y < cave->h; y++)
+  {
+    for (x = 0; x < cave->w; x++)
+    {
+      int index = y * cave->w + x;
+
+      cave->map[y][x] = import(uncompressed[index], index);
+    }
+  }
+
+  // crli has no levels
+  for (i = 0; i < 5; i++)
+  {
+    cave->level_time[i] = (int)uncompressed[0x370] * 100 + uncompressed[0x371] * 10 + uncompressed[0x372];
+
+    // same as gate opening after 0 diamonds
+    if (cave->level_time[i] == 0)
+      cave->level_time[i] = 1000;
+
+    cave->level_diamonds[i] = (int)uncompressed[0x373] * 100 + uncompressed[0x374] * 10 + uncompressed[0x375];
+
+    // gate opening is checked AFTER adding to diamonds collected, so 0 here is 1000 (!) needed
+    if (cave->level_diamonds[i] == 0)
+      cave->level_diamonds[i] = 1000;
+
+    cave->level_ckdelay[i] = uncompressed[0x38A];
+    cave->level_amoeba_time[i] = (int)uncompressed[0x37C] * 256 + uncompressed[0x37D];
+
+    // 0 immediately underflowed to 999, so we use 999. example: sendydash 3, cave 02.
+    if (cave->level_amoeba_time[i] == 0)
+      cave->level_amoeba_time[i] = 999;
+
+    cave->level_magic_wall_time[i] = (int)uncompressed[0x37E] * 256 + uncompressed[0x37F];
+    cave->level_slime_permeability_c64[i] = uncompressed[0x38B];
+    cave->level_bonus_time[i] = uncompressed[0x392];
+    cave->level_penalty_time[i] = uncompressed[0x393];
+    cave->level_amoeba_threshold[i] = 256 * (int)uncompressed[0x390] + uncompressed[0x390 + 1];
+  }
+
+  cave->extra_diamond_value = (int)uncompressed[0x376] * 100 + uncompressed[0x377] * 10 + uncompressed[0x378];
+  cave->diamond_value = (int)uncompressed[0x379] * 100 + uncompressed[0x37A] * 10 + uncompressed[0x37B];
+
+  if (uncompressed[0x380])
+    cave->creatures_direction_auto_change_time = uncompressed[0x381];
+
+  cave->colorb = gd_c64_color(uncompressed[0x384] & 0xf);    // border
+  cave->color0 = gd_c64_color(uncompressed[0x385] & 0xf);
+  cave->color1 = gd_c64_color(uncompressed[0x386] & 0xf);
+  cave->color2 = gd_c64_color(uncompressed[0x387] & 0xf);
+  cave->color3 = gd_c64_color(uncompressed[0x388] & 0x7);    // lower 3 bits only!
+  cave->color4 = cave->color3;
+  cave->color5 = cave->color1;
+
+  cave->intermission = uncompressed[0x389] != 0;
+
+  // if it is intermission but not scrollable
+  if (cave->intermission && !uncompressed[0x38c])
+  {
+    cave->x2 = 19;
+    cave->y2 = 11;
+  }
+
+  /*
+    AMOEBA in crazy dash 8:
+    jsr $2500        ; generate true random
+    and $94            ; binary and the current "probability"
+    cmp #$04        ; compare to 4
+    bcs out            ; jump out (do not expand) if carry set, ie. result was less than 4.
+
+    prob values can be like num = 3, 7, 15, 31, 63, ... n lsb bits count.
+    0..3>=4?  0..7>=4?  0..15>=4? and similar.
+    this way, probability of growing is 4/(num+1)
+  */
+
+  // probabilities store * 1M
+  cave->amoeba_growth_prob = (1E6 * 4.0 / (uncompressed[0x382] + 1)) + 0.5;
+
+  if (cave->amoeba_growth_prob > 1000000)
+    cave->amoeba_growth_prob = 1000000;
+
+  cave->amoeba_fast_growth_prob = (1E6*4.0/(uncompressed[0x383] + 1)) + 0.5;
+
+  if (cave->amoeba_fast_growth_prob > 1000000)
+    cave->amoeba_fast_growth_prob = 1000000;
+
+  // 2c was a normal switch, 2d a changed one.
+  cave->creatures_backwards = uncompressed[0x38f] == 0x2d;
+  cave->magic_wall_sound = uncompressed[0x38d] == 0xf1;
+
+  // 2e horizontal, 2f vertical. we implement this by changing them
+  if (uncompressed[0x38e] == 0x2f)
+  {
+    for (y = 0; y < cave->h; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       if (cave->map[y][x] == O_H_EXPANDING_WALL)
+         cave->map[y][x] = O_V_EXPANDING_WALL;
+      }
+    }
+  }
+
+  cave->biter_delay_frame      = uncompressed[0x394];
+  cave->magic_wall_stops_amoeba        = uncompressed[0x395] == 0;    // negated!!
+  cave->bomb_explosion_effect  = import(uncompressed[0x396], 0x396);
+  cave->explosion_effect       = import(uncompressed[0x397], 0x397);
+  cave->stone_bouncing_effect  = import(uncompressed[0x398], 0x398);
+  cave->diamond_birth_effect   = import(uncompressed[0x399], 0x399);
+  cave->magic_diamond_to       = import(uncompressed[0x39a], 0x39a);
+
+  cave->bladder_converts_by    = import(uncompressed[0x39b], 0x39b);
+  cave->diamond_falling_effect = import(uncompressed[0x39c], 0x39c);
+  cave->biter_eat              = import(uncompressed[0x39d], 0x39d);
+  cave->slime_eats_1           = import(uncompressed[0x39e], 0x39e);
+  cave->slime_converts_1       = import(uncompressed[0x39e] + 3, 0x39e);
+  cave->slime_eats_2           = import(uncompressed[0x39f], 0x39f);
+  cave->slime_converts_2       = import(uncompressed[0x39f] + 3, 0x39f);
+
+  // v3.0 has some new properties.
+  if (version >= V3_0)
+  {
+    cave->diagonal_movements    = uncompressed[0x3a4] != 0;
+    cave->amoeba_too_big_effect         = import(uncompressed[0x3a6], 0x3a6);
+    cave->amoeba_enclosed_effect = import(uncompressed[0x3a7], 0x3a7);
+
+    /*
+      acid in crazy dream 8:
+      jsr $2500    ; true random
+      cmp    $03a8    ; compare to ratio
+      bcs out        ; if it was smaller, forget it for now.
+
+      ie. random<=ratio, then acid grows.
+    */
+
+    // * 1e6, probabilities are stored as int
+    cave->acid_spread_ratio            = uncompressed[0x3a8] / 255.0 * 1E6;
+    cave->acid_eats_this               = import(uncompressed[0x3a9], 0x3a9);
+    cave->expanding_wall_looks_like    = import(uncompressed[0x3ab], 0x3ab);
+    cave->dirt_looks_like              = import(uncompressed[0x3ac], 0x3ac);
+  }
+  else
+  {
+    // version is <= 3.0, so this is a 1stb cave.
+    // the only parameters, for which this matters, are these:
+    if (uncompressed[0x380] != 0)
+      cave->creatures_direction_auto_change_time = uncompressed[0x381];
+    else
+      cave->diagonal_movements = uncompressed[0x381] != 0;
+  }
+
+  if (cavefile)
+    cave->selectable = !cave->intermission;     // best we can do
+  else
+    cave->selectable = !data[0];                // given by converter
+
+  return datapos;
+}
+
+GdCavefileFormat gd_caveset_imported_get_format(const byte *buf)
+{
+  const char *s_bd1       = "GDashBD1";
+  const char *s_bd1_atari = "GDashB1A";
+  const char *s_dc1       = "GDashDC1";
+  const char *s_bd2       = "GDashBD2";
+  const char *s_bd2_atari = "GDashB2A";
+  const char *s_plc       = "GDashPLC";
+  const char *s_plc_atari = "GDashPCA";
+  const char *s_dlb       = "GDashDLB";
+  const char *s_crl       = "GDashCRL";
+  const char *s_cd7       = "GDashCD7";
+  const char *s_cd9       = "GDashCD9";
+  const char *s_1st       = "GDash1ST";
+
+  if (memcmp((char *)buf, s_bd1, strlen(s_bd1)) == 0)
+    return GD_FORMAT_BD1;
+  if (memcmp((char *)buf, s_bd1_atari, strlen(s_bd1_atari)) == 0)
+    return GD_FORMAT_BD1_ATARI;
+  if (memcmp((char *)buf, s_dc1, strlen(s_dc1)) == 0)
+    return GD_FORMAT_DC1;
+  if (memcmp((char *)buf, s_bd2, strlen(s_bd2)) == 0)
+    return GD_FORMAT_BD2;
+  if (memcmp((char *)buf, s_bd2_atari, strlen(s_bd2_atari)) == 0)
+    return GD_FORMAT_BD2_ATARI;
+  if (memcmp((char *)buf, s_plc, strlen(s_plc)) == 0)
+    return GD_FORMAT_PLC;
+  if (memcmp((char *)buf, s_plc_atari, strlen(s_plc_atari)) == 0)
+    return GD_FORMAT_PLC_ATARI;
+  if (memcmp((char *)buf, s_dlb, strlen(s_dlb)) == 0)
+    return GD_FORMAT_DLB;
+  if (memcmp((char *)buf, s_crl, strlen(s_crl)) == 0)
+    return GD_FORMAT_CRLI;
+  if (memcmp((char *)buf, s_cd7, strlen(s_cd7)) == 0)
+    return GD_FORMAT_CRDR_7;
+  if (memcmp((char *)buf, s_cd9, strlen(s_cd9)) == 0)
+    return GD_FORMAT_CRDR_9;
+  if (memcmp((char *)buf, s_1st, strlen(s_1st)) == 0)
+    return GD_FORMAT_FIRSTB;
+
+  return GD_FORMAT_UNKNOWN;
+}
+
+
+// ----------------------------------------------------------------------------
+//  Load caveset from memory buffer.
+//  Loads the caveset from a memory buffer.
+//  returns: List * of caves.
+// ----------------------------------------------------------------------------
+
+List *gd_caveset_import_from_buffer (const byte *buf, size_t length)
+{
+  boolean numbering;
+  int cavenum, intermissionnum, num;
+  int cavelength, bufp;
+  List *caveset = NULL, *iter;
+  unsigned int encodedlength;
+  GdCavefileFormat format;
+
+  if (length != -1 && length < 12)
+  {
+    Warn("buffer too short to be a GDash datafile");
+    return NULL;
+  }
+
+  encodedlength = (unsigned int)(*((unsigned int *)(buf + 8)));
+  if (length != -1 && encodedlength != length - 12)
+  {
+    Warn("file length and data size mismatch in GDash datafile");
+    return NULL;
+  }
+
+  format = gd_caveset_imported_get_format(buf);
+  if (format == GD_FORMAT_UNKNOWN)
+  {
+    Warn("buffer does not contain a GDash datafile");
+    return NULL;
+  }
+
+  buf += 12;
+  length = encodedlength;
+
+  bufp = 0;
+  cavenum = 0;
+
+  while (bufp < length)
+  {
+    GdCave *newcave;
+    // default is to append cave to caveset; list_insert appends when pos = -1
+    int insertpos = -1;
+
+    newcave = gd_cave_new();
+
+    cavelength = 0;    // to avoid compiler warning
+
+    switch (format)
+    {
+      case GD_FORMAT_BD1:                // boulder dash 1
+      case GD_FORMAT_BD1_ATARI:          // boulder dash 1, atari version
+      case GD_FORMAT_DC1:                // deluxe caves 1
+      case GD_FORMAT_BD2:                // boulder dash 2
+      case GD_FORMAT_BD2_ATARI:          // boulder dash 2
+       // these are not in the data so we guess
+       newcave->selectable = (cavenum < 16) && (cavenum % 4 == 0);
+       newcave->intermission = cavenum > 15;
+
+       // no name, so we make up one
+       if (newcave->intermission)
+         snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum - 15);
+       else
+         snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A' + cavenum);
+
+       switch(format)
+       {
+         case GD_FORMAT_BD1:
+         case GD_FORMAT_BD1_ATARI:
+         case GD_FORMAT_DC1:
+           cavelength = cave_copy_from_bd1(newcave, buf + bufp, length - bufp, format);
+           break;
+         case GD_FORMAT_BD2:
+         case GD_FORMAT_BD2_ATARI:
+           cavelength = cave_copy_from_bd2(newcave, buf + bufp, length - bufp, format);
+           break;
+
+         default:
+           break;
+       };
+
+       // original bd1 had level order ABCDEFGH... and then the last four were the intermissions.
+       // those should be inserted between D-E, H-I... caves.
+       if (cavenum > 15)
+         insertpos = (cavenum - 15) * 5 - 1;
+       break;
+
+      case GD_FORMAT_FIRSTB:
+       cavelength = cave_copy_from_1stb(newcave, buf + bufp, length - bufp);
+
+       // every fifth cave (4+1 intermission) is selectable.
+       newcave->selectable = cavenum % 5 == 0;
+       break;
+
+      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);
+       break;
+
+      case GD_FORMAT_DLB:
+       // no one's delight boulder dash, something like rle compressed plck caves
+       // but there are 20 of them, as if it was a bd1 or bd2 game.
+       // also num%5 = 4 is intermission.
+       // we have to set intermission flag on our own, as the file did not contain
+       // the info explicitly
+
+       newcave->intermission = (cavenum % 5) == 4;
+       if (newcave->intermission)
+       {
+         // also set visible size
+         newcave->x2 = 19;
+         newcave->y2 = 11;
+       }
+
+       newcave->selectable = cavenum % 5 == 0;    // original selection scheme
+       if (newcave->intermission)
+         snprintf(newcave->name, sizeof(newcave->name), _("Intermission %d"), cavenum / 5 + 1);
+       else
+         snprintf(newcave->name, sizeof(newcave->name), _("Cave %c"), 'A'+(cavenum % 5 + cavenum / 5 * 4));
+
+       cavelength = cave_copy_from_dlb (newcave, buf + bufp, length - bufp);
+       break;
+
+      case GD_FORMAT_CRLI:
+       cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
+       break;
+
+      case GD_FORMAT_CRDR_7:
+       cavelength = cave_copy_from_crdr_7 (newcave, buf + bufp, length - bufp);
+       break;
+
+      case GD_FORMAT_CRDR_9:
+       cavelength = cave_copy_from_crli (newcave, buf + bufp, length - bufp);
+       if (cavelength != -1)
+         crazy_dream_9_add_specials(newcave, buf, cavelength);
+       break;
+
+      case GD_FORMAT_UNKNOWN:
+       break;
+    }
+
+    if (cavelength == -1)
+    {
+      gd_cave_free(newcave);
+
+      Error("Aborting cave import.");
+      break;
+    }
+    else
+    {
+      caveset = list_insert(caveset, newcave, insertpos);
+    }
+
+    cavenum++;
+    bufp += cavelength;
+
+    // hack: some dlb files contain junk data after 20 caves.
+    if (format == GD_FORMAT_DLB && cavenum == 20)
+    {
+      if (bufp < length)
+       Warn("excess data in dlb file, %d bytes", (int)(length-bufp));
+      break;
+    }
+  }
+
+  // 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))
+    {
+      List *iter;
+      int n;
+      boolean standard;
+
+      standard = (list_length(caveset)%5) == 0;    // cave count % 5 != 0 -> nonstandard
+
+      for (n = 0, iter = caveset; iter != NULL; n++, iter = iter->next)
+      {
+       GdCave *cave = iter->data;
+
+       if ((n % 5 == 4 && !cave->intermission) ||
+           (n % 5 != 4 && cave->intermission))
+         standard = FALSE;    // 4 cave, 1 intermission
+      }
+
+      // if test passed, update selectability
+      if (standard)
+       for (n = 0, iter = caveset; iter != NULL; n++, iter = iter->next)
+       {
+         GdCave *cave = iter->data;
+
+         // update "selectable"
+         cave->selectable = (n % 5) == 0;
+       }
+    }
+
+  // try to give some names for the caves
+  cavenum = 1;
+  intermissionnum = 1;
+  num = 1;
+
+  // use numbering instead of letters, if following formats or too many caves
+  // (as we would run out of letters)
+  numbering = format == GD_FORMAT_PLC || format == GD_FORMAT_CRLI || list_length(caveset) > 26;
+
+  for (iter = caveset; iter != NULL; iter = iter->next)
+  {
+    GdCave *cave = (GdCave *)iter->data;
+
+    if (!strEqual(cave->name, ""))    // if it already has a name, skip
+      continue;
+
+    if (cave->intermission)
+    {
+      // intermission
+      if (numbering)
+       snprintf(cave->name, sizeof(cave->name), _("Intermission %02d"), num);
+      else
+       snprintf(cave->name, sizeof(cave->name), _("Intermission %d"), intermissionnum);
+    } else {
+      if (numbering)
+       snprintf(cave->name, sizeof(cave->name), _("Cave %02d"), num);
+      else
+       snprintf(cave->name, sizeof(cave->name), _("Cave %c"), 'A' - 1 + cavenum);
+    }
+
+    num++;
+    if (cave->intermission)
+      intermissionnum++;
+    else
+      cavenum++;
+  }
+
+  // if the user requests, we make all caves selectable. intermissions not.
+  if (gd_import_as_all_caves_selectable)
+  {
+    for (iter = caveset; iter != NULL; iter = iter->next)
+    {
+      GdCave *cave = (GdCave *)iter->data;
+
+      // make selectable if not an intermission.
+      // also selectable, if it was selectable originally, for some reason.
+      cave->selectable = cave->selectable || !cave->intermission;
+    }
+  }
+
+  return caveset;
+}
+
+// to be called at program start.
+void gd_c64_import_init_tables(void)
+{
+}
diff --git a/src/game_bd/bd_c64import.h b/src/game_bd/bd_c64import.h
new file mode 100644 (file)
index 0000000..979b425
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVEIMPORT_H
+#define BD_CAVEIMPORT_H
+
+#include "bd_cave.h"
+
+
+extern const char gd_bd_internal_chars[];
+extern const GdElement gd_crazylight_import_table[];
+
+// file formats
+typedef enum _gd_cavefile_format
+{
+  GD_FORMAT_UNKNOWN,    // unknown format
+  GD_FORMAT_BD1,        // boulder dash 1
+  GD_FORMAT_BD1_ATARI,  // boulder dash 1 atari version
+  GD_FORMAT_DC1,        // boulder dash 1, deluxe caves 1 extension - non-sloped brick wall
+  GD_FORMAT_BD2,        // boulder dash 2 with rockford's extensions
+  GD_FORMAT_BD2_ATARI,  // boulder dash 2, atari version
+  GD_FORMAT_PLC,        // peter liepa construction kit
+  GD_FORMAT_PLC_ATARI,  // peter liepa construction kit, atari version
+  GD_FORMAT_DLB,        // no one's delight boulder dash
+  GD_FORMAT_CRLI,       // crazy light construction kit
+  GD_FORMAT_CRDR_7,     // crazy dream 7
+  GD_FORMAT_CRDR_9,     // crazy dream 9 - is a crli caveset with hardcoded mazes
+  GD_FORMAT_FIRSTB,     // first boulder
+} GdCavefileFormat;
+
+// engines
+typedef enum _gd_engine
+{
+  GD_ENGINE_BD1,
+  GD_ENGINE_BD2,
+  GD_ENGINE_PLCK,
+  GD_ENGINE_1STB,
+  GD_ENGINE_CRDR7,
+  GD_ENGINE_CRLI,
+  GD_ENGINE_INVALID,    // fake
+} GdEngine;
+
+extern const char *gd_engines[];
+
+GdCavefileFormat gd_caveset_imported_get_format(const unsigned char *buf);
+List* gd_caveset_import_from_buffer (const unsigned char *buf, size_t length);
+
+void gd_cave_set_engine_defaults(GdCave *cave, GdEngine engine);
+GdEngine gd_cave_get_engine_from_string(const char *param);
+GdPropertyDefault *gd_get_engine_default_array(GdEngine engine);
+
+void gd_c64_import_init_tables(void);
+
+#endif // BD_CAVEIMPORT_H
diff --git a/src/game_bd/bd_cave.c b/src/game_bd/bd_cave.c
new file mode 100644 (file)
index 0000000..6a22a63
--- /dev/null
@@ -0,0 +1,1737 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+// arrays for movements
+// also no1 and bd2 cave data import helpers; line direction coordinates
+const int gd_dx[] =
+{
+  0, 0, 1, 1, 1, 0, -1, -1, -1, 0, 2, 2, 2, 0, -2, -2, -2
+};
+const int gd_dy[] =
+{
+  0, -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, 0, 2, 2, 2, 0, -2
+};
+
+// TRANSLATORS:
+// None here means "no direction to move"; when there is no gravity while stirring the pot.
+static const char* direction_name[] =
+{
+  N_("None"),
+  N_("Up"),
+  N_("Up+right"),
+  N_("Right"),
+  N_("Down+right"),
+  N_("Down"),
+  N_("Down+left"),
+  N_("Left"),
+  N_("Up+left")
+};
+
+static const char* direction_filename[] =
+{
+  "none",
+  "up",
+  "upright",
+  "right",
+  "downright",
+  "down",
+  "downleft",
+  "left",
+  "upleft"
+};
+
+static const char* scheduling_name[] =
+{
+  N_("Milliseconds"),
+  "BD1",
+  "BD2",
+  "Construction Kit",
+  "Crazy Dream 7",
+  "Atari BD1",
+  "Atari BD2/Construction Kit"
+};
+
+static const char* scheduling_filename[] =
+{
+  "ms",
+  "bd1",
+  "bd2",
+  "plck",
+  "crdr7",
+  "bd1atari",
+  "bd2ckatari"
+};
+
+static HashTable *name_to_element;
+GdElement gd_char_to_element[256];
+
+// color of flashing the screen, gate opening to exit
+const GdColor gd_flash_color = 0xFFFFC0;
+
+// selected object in editor
+const GdColor gd_select_color = 0x8080FF;
+
+// direction to string and vice versa
+const char *gd_direction_get_visible_name(GdDirection dir)
+{
+  return direction_name[dir];
+}
+
+const char *gd_direction_get_filename(GdDirection dir)
+{
+  return direction_filename[dir];
+}
+
+GdDirection gd_direction_from_string(const char *str)
+{
+  int i;
+
+  for (i = 1; i < ARRAY_SIZE(direction_filename); i++)
+    if (strcasecmp(str, direction_filename[i]) == 0)
+      return (GdDirection) i;
+
+  Warn("invalid direction name '%s', defaulting to down", str);
+  return GD_MV_DOWN;
+}
+
+// scheduling name to string and vice versa
+const char *gd_scheduling_get_filename(GdScheduling sched)
+{
+  return scheduling_filename[sched];
+}
+
+const char *gd_scheduling_get_visible_name(GdScheduling sched)
+{
+  return scheduling_name[sched];
+}
+
+GdScheduling gd_scheduling_from_string(const char *str)
+{
+  int i;
+
+  for (i = 0; i < ARRAY_SIZE(scheduling_filename); i++)
+    if (strcasecmp(str, scheduling_filename[i]) == 0)
+      return (GdScheduling) i;
+
+  Warn("invalid scheduling name '%s', defaulting to plck", str);
+
+  return GD_SCHEDULING_PLCK;
+}
+
+/*
+  fill a given struct with default properties.
+  "str" is the struct (data),
+  "properties" describes the structure and its pointers,
+  "defaults" are the pieces of data which will be copied to str.
+*/
+void gd_struct_set_defaults_from_array(void *str,
+                                      const GdStructDescriptor *properties,
+                                      GdPropertyDefault *defaults)
+{
+  int i;
+
+  for (i = 0; defaults[i].offset != -1; i++)
+  {
+    void *pvalue = STRUCT_MEMBER_P(str, defaults[i].offset);
+    // these point to the same, but to avoid the awkward cast syntax
+    int *ivalue = pvalue;
+    GdElement *evalue = pvalue;
+    GdDirection *dvalue = pvalue;
+    GdScheduling *svalue = pvalue;
+    boolean *bvalue = pvalue;
+    GdColor *cvalue = pvalue;
+    int j, n;
+
+    // check which property we are talking about: find it in gd_cave_properties.
+    n = defaults[i].property_index;
+    if (n == 0)
+    {
+      while (properties[n].identifier != NULL &&
+            properties[n].offset != defaults[i].offset)
+       n++;
+
+      // remember so we will be fast later
+      defaults[i].property_index = n;
+    }
+
+    // some properties are arrays. this loop fills all with the same values
+    for (j = 0; j < properties[n].count; j++)
+    {
+      switch (properties[n].type)
+      {
+       // these are for the gui; do nothing
+       case GD_TAB:
+       case GD_LABEL:
+         // no default value for strings
+       case GD_TYPE_STRING:
+       case GD_TYPE_LONGSTRING:
+         break;
+
+       case GD_TYPE_RATIO:
+         // this is also an integer, difference is only when saving to bdcff
+       case GD_TYPE_INT:
+         if (defaults[i].defval < properties[n].min ||
+             defaults[i].defval > properties[n].max)
+           Warn("integer property %s out of range", properties[n].identifier);
+         ivalue[j] = defaults[i].defval;
+         break;
+
+       case GD_TYPE_PROBABILITY:
+         // floats are stored as integer, /million; but are integers
+         if (defaults[i].defval < 0 ||
+             defaults[i].defval > 1000000)
+           Warn("integer property %s out of range", properties[n].identifier);
+         ivalue[j] = defaults[i].defval;
+         break;
+
+       case GD_TYPE_BOOLEAN:
+         bvalue[j] = defaults[i].defval != 0;
+         break;
+
+       case GD_TYPE_ELEMENT:
+       case GD_TYPE_EFFECT:
+         evalue[j] = (GdElement) defaults[i].defval;
+         break;
+
+       case GD_TYPE_COLOR:
+         cvalue[j] = gd_c64_color(defaults[i].defval);
+         break;
+
+       case GD_TYPE_DIRECTION:
+         dvalue[j] = (GdDirection) defaults[i].defval;
+         break;
+
+       case GD_TYPE_SCHEDULING:
+         svalue[j] = (GdScheduling) defaults[i].defval;
+         break;
+      }
+    }
+  }
+}
+
+/*
+  creates the character->element conversion table; using
+  the fixed-in-the-bdcff characters. later, this table
+  may be filled with more elements.
+*/
+void gd_create_char_to_element_table(void)
+{
+  int i;
+
+  // fill all with unknown
+  for (i = 0; i < ARRAY_SIZE(gd_char_to_element); i++)
+    gd_char_to_element[i] = O_UNKNOWN;
+
+  // then set fixed characters
+  for (i = 0; i < O_MAX; i++)
+  {
+    int c = gd_elements[i].character;
+
+    if (c)
+    {
+      if (gd_char_to_element[c] != O_UNKNOWN)
+       Warn("Character %c already used for element %x", c, gd_char_to_element[c]);
+
+      gd_char_to_element[c] = i;
+    }
+  }
+}
+
+// search the element database for the specified character, and return the element.
+GdElement gd_get_element_from_character (byte character)
+{
+  if (gd_char_to_element[character] != O_UNKNOWN)
+    return gd_char_to_element[character];
+
+  Warn ("Invalid character representing element: %c", character);
+
+  return O_UNKNOWN;
+}
+
+/*
+  do some init; this function is to be called at the start of the application
+*/
+void gd_cave_init(void)
+{
+  int i;
+
+  // put names to a hash table
+  // this is a helper for file read operations
+  // maps copied strings to elements (integers)
+  name_to_element = create_hashtable(gd_str_case_hash, gd_str_case_equal, NULL, NULL);
+
+  for (i = 0; i < O_MAX; i++)
+  {
+    char *key;
+
+    key = getStringToUpper(gd_elements[i].filename);
+
+    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, INT_TO_PTR(i));
+    // ^^^ do not free "key", as hash table needs it during the whole time!
+
+    key = getStringCat2("SCANNED_", key);              // new string
+
+    hashtable_insert(name_to_element, key, INT_TO_PTR(i));
+    // once again, do not free "key" ^^^
+  }
+
+  // for compatibility with tim stridmann's memorydump->bdcff converter... .... ...
+  hashtable_insert(name_to_element, "HEXPANDING_WALL", INT_TO_PTR(O_H_EXPANDING_WALL));
+  hashtable_insert(name_to_element, "FALLING_DIAMOND", INT_TO_PTR(O_DIAMOND_F));
+  hashtable_insert(name_to_element, "FALLING_BOULDER", INT_TO_PTR(O_STONE_F));
+  hashtable_insert(name_to_element, "EXPLOSION1S", INT_TO_PTR(O_EXPLODE_1));
+  hashtable_insert(name_to_element, "EXPLOSION2S", INT_TO_PTR(O_EXPLODE_2));
+  hashtable_insert(name_to_element, "EXPLOSION3S", INT_TO_PTR(O_EXPLODE_3));
+  hashtable_insert(name_to_element, "EXPLOSION4S", INT_TO_PTR(O_EXPLODE_4));
+  hashtable_insert(name_to_element, "EXPLOSION5S", INT_TO_PTR(O_EXPLODE_5));
+  hashtable_insert(name_to_element, "EXPLOSION1D", INT_TO_PTR(O_PRE_DIA_1));
+  hashtable_insert(name_to_element, "EXPLOSION2D", INT_TO_PTR(O_PRE_DIA_2));
+  hashtable_insert(name_to_element, "EXPLOSION3D", INT_TO_PTR(O_PRE_DIA_3));
+  hashtable_insert(name_to_element, "EXPLOSION4D", INT_TO_PTR(O_PRE_DIA_4));
+  hashtable_insert(name_to_element, "EXPLOSION5D", INT_TO_PTR(O_PRE_DIA_5));
+  hashtable_insert(name_to_element, "WALL2", INT_TO_PTR(O_STEEL_EXPLODABLE));
+
+  // compatibility with old bd-faq (pre disassembly of bladder)
+  hashtable_insert(name_to_element, "BLADDERd9", INT_TO_PTR(O_BLADDER_8));
+
+  // create table to show errors at the start of the application
+  gd_create_char_to_element_table();
+}
+
+// search the element database for the specified name, and return the element
+GdElement gd_get_element_from_string (const char *string)
+{
+  char *upper = getStringToUpper(string);
+  void *value;
+  boolean found;
+
+  if (!string)
+  {
+    Warn("Invalid string representing element: (null)");
+    return O_UNKNOWN;
+  }
+
+  found = hashtable_exists(name_to_element, upper);    // hash value may be 0
+  if (found)
+    value = hashtable_search(name_to_element, upper);
+  free(upper);
+  if (found)
+    return (GdElement) (PTR_TO_INT(value));
+
+  Warn("Invalid string representing element: '%s'", string);
+
+  return O_UNKNOWN;
+}
+
+void gd_cave_set_defaults_from_array(GdCave* cave, GdPropertyDefault *defaults)
+{
+  gd_struct_set_defaults_from_array(cave, gd_cave_properties, defaults);
+}
+
+/*
+  load default values from description array
+  these are default for gdash and bdcff.
+*/
+void gd_cave_set_gdash_defaults(GdCave* cave)
+{
+  int i;
+
+  gd_cave_set_defaults_from_array(cave, gd_cave_defaults_gdash);
+
+  // these did not fit into the descriptor array
+  for (i = 0; i < 5; i++)
+  {
+    cave->level_rand[i] = i;
+    cave->level_timevalue[i] = i + 1;
+  }
+}
+
+// for quicksort. compares two highscores.
+int gd_highscore_compare(const void *a, const void *b)
+{
+  const GdHighScore *ha = a;
+  const GdHighScore *hb = b;
+  return hb->score - ha->score;
+}
+
+void gd_clear_highscore(GdHighScore *hs)
+{
+  int i;
+
+  for (i = 0; i < GD_HIGHSCORE_NUM; i++)
+  {
+    strcpy(hs[i].name, "");
+    hs[i].score = 0;
+  }
+}
+
+boolean gd_has_highscore(GdHighScore *hs)
+{
+  return hs[0].score > 0;
+}
+
+// return true if score achieved is a highscore
+boolean gd_is_highscore(GdHighScore *scores, int score)
+{
+  // if score is above zero AND bigger than the last one
+  if (score > 0 && score > scores[GD_HIGHSCORE_NUM-1].score)
+    return TRUE;
+
+  return FALSE;
+}
+
+int gd_add_highscore(GdHighScore *highscores, const char *name, int score)
+{
+  int i;
+
+  if (!gd_is_highscore(highscores, score))
+    return -1;
+
+  // overwrite the last one
+  gd_strcpy(highscores[GD_HIGHSCORE_NUM-1].name, name);
+  highscores[GD_HIGHSCORE_NUM-1].score = score;
+
+  // and sort
+  qsort(highscores, GD_HIGHSCORE_NUM, sizeof(GdHighScore), gd_highscore_compare);
+
+  for (i = 0; i < GD_HIGHSCORE_NUM; i++)
+    if (strEqual(highscores[i].name, name) && highscores[i].score == score)
+      return i;
+
+  return -1;
+}
+
+// for the case-insensitive hash keys
+int gd_str_case_equal(void *s1, void *s2)
+{
+  return strcasecmp(s1, s2) == 0;
+}
+
+unsigned int gd_str_case_hash(void *v)
+{
+  char *upper = getStringToUpper(v);
+  unsigned int hash = get_hash_from_string(upper);
+
+  free(upper);
+
+  return hash;
+}
+
+/*
+  create new cave with default values.
+  sets every value, also default size, diamond value etc.
+*/
+GdCave *gd_cave_new(void)
+{
+  GdCave *cave;
+
+  cave = checked_calloc(sizeof(GdCave));
+
+  // hash table which stores unknown tags as strings.
+  cave->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
+
+  gd_cave_set_gdash_defaults(cave);
+
+  return cave;
+}
+
+/*
+  cave maps.
+  cave maps are continuous areas in memory. the allocated memory
+  is width * height * bytes_per_cell long.
+  the cave map[0] stores the pointer given by g_malloc().
+  the map itself is also an allocated array of pointers to the
+  beginning of rows.
+  therefore:
+  rows = new (pointers to rows);
+  rows[0] = new map
+  rows[1..h-1] = rows[0] + width * bytes
+
+  freeing this:
+  free(rows[0])
+  free(rows)
+*/
+
+/*
+  allocate a cave map-like array, and initialize to zero.
+  one cell is cell_size bytes long.
+*/
+void *gd_cave_map_new_for_cave(const GdCave *cave, const int cell_size)
+{
+  void **rows;                // this is void**, pointer to array of ...
+  int y;
+
+  rows = checked_malloc((cave->h) * sizeof(void *));
+  rows[0] = checked_calloc(cell_size * cave->w * cave->h);
+
+  for (y = 1; y < cave->h; y++)
+    // base pointer + num_of_bytes_per_element * width * number_of_row; as sizeof(char) = 1
+    rows[y] = (char *)rows[0] + cell_size * cave->w * y;
+
+  return rows;
+}
+
+/*
+  duplicate map
+
+  if map is null, this also returns null.
+*/
+void *gd_cave_map_dup_size(const GdCave *cave, const void *map, const int cell_size)
+{
+  void **rows;
+  void **maplines = (void **)map;
+  int y;
+
+  if (!map)
+    return NULL;
+
+  rows = checked_malloc((cave->h) * sizeof(void *));
+  rows[0] = get_memcpy (maplines[0], cell_size * cave->w * cave->h);
+
+  for (y = 1; y < cave->h; y++)
+    rows[y] = (char *)rows[0] + cell_size * cave->w * y;
+
+  return rows;
+}
+
+void gd_cave_map_free(void *map)
+{
+  void **maplines = (void **) map;
+
+  if (!map)
+    return;
+
+  free(maplines[0]);
+  free(map);
+}
+
+/*
+  frees memory associated to cave
+*/
+void gd_cave_free(GdCave *cave)
+{
+  int i;
+
+  if (!cave)
+    return;
+
+  if (cave->tags)
+    hashtable_destroy(cave->tags);
+
+  if (cave->random)    // random generator is a GdRand *
+    gd_rand_free(cave->random);
+
+  // free strings
+  for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
+    if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
+      checked_free(STRUCT_MEMBER(char *, cave, gd_cave_properties[i].offset));
+
+  // map
+  gd_cave_map_free(cave->map);
+
+  // rendered data
+  gd_cave_map_free(cave->objects_order);
+
+  // hammered walls to reappear data
+  gd_cave_map_free(cave->hammered_reappear);
+
+  // free objects
+  list_foreach(cave->objects, (list_fn) free, NULL);
+  list_free(cave->objects);
+
+  // free replays
+  list_foreach(cave->replays, (list_fn) gd_replay_free, NULL);
+  list_free(cave->replays);
+
+  // freeing main pointer
+  free (cave);
+}
+
+static void hash_copy_foreach(const char *key, const char *value, HashTable *dest)
+{
+  hashtable_insert(dest, getStringCopy(key), getStringCopy(value));
+}
+
+// copy cave from src to destination, with duplicating dynamically allocated data
+void gd_cave_copy(GdCave *dest, const GdCave *src)
+{
+  int i;
+
+  // copy entire data
+  memmove(dest, src, sizeof(GdCave));
+
+  // but duplicate dynamic data
+  dest->tags = create_hashtable(gd_str_case_hash, gd_str_case_equal, free, free);
+
+  if (src->tags)
+    hashtable_foreach(src->tags, (hashtable_fn)hash_copy_foreach, dest->tags);
+
+  dest->map = gd_cave_map_dup(src, map);
+  dest->hammered_reappear = gd_cave_map_dup(src, hammered_reappear);
+
+  // for longstrings
+  for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
+    if (gd_cave_properties[i].type == GD_TYPE_LONGSTRING)
+      STRUCT_MEMBER(char *, dest, gd_cave_properties[i].offset) =
+       getStringCopy(STRUCT_MEMBER(char *, src, gd_cave_properties[i].offset));
+
+  // no reason to copy this
+  dest->objects_order = NULL;
+
+  // copy objects list
+  if (src->objects)
+  {
+    List *iter;
+
+    dest->objects = NULL;    // new empty list
+    for (iter = src->objects; iter != NULL; iter = iter->next) // do a deep copy
+      dest->objects = list_append(dest->objects, get_memcpy (iter->data, sizeof (GdObject)));
+  }
+
+  // copy replays
+  if (src->replays)
+  {
+    List *iter;
+
+    dest->replays = NULL;
+    for (iter = src->replays; iter != NULL; iter = iter->next) // do a deep copy
+      dest->replays = list_append(dest->replays, gd_replay_new_from_replay(iter->data));
+  }
+
+  // copy random number generator
+  if (src->random)
+    dest->random = gd_rand_copy(src->random);
+}
+
+// create new cave, which is a copy of the cave given.
+GdCave *gd_cave_new_from_cave(const GdCave *orig)
+{
+  GdCave *cave;
+
+  cave = gd_cave_new();
+  gd_cave_copy(cave, orig);
+
+  return cave;
+}
+
+/*
+  Put an object to the specified position.
+  Performs range checking.
+  If wraparound objects are selected, wraps around x coordinates, with or without lineshift.
+  (The y coordinate is not wrapped, as it did not work like that on the c64)
+  order is a pointer to the GdObject describing this object. Thus the editor can identify
+  which cell was created by which object.
+*/
+void gd_cave_store_rc(GdCave *cave, int x, int y, const GdElement element, const void *order)
+{
+  // if we do not need to draw, exit now
+  if (element == O_NONE)
+    return;
+
+  // check bounds
+  if (cave->wraparound_objects)
+  {
+    if (cave->lineshift)
+    {
+      // fit x coordinate within range, with correcting y at the same time
+      while (x < 0)
+      {
+       x += cave->w;    // out of bounds on the left...
+       y--;             // previous row
+      }
+
+      while (x >= cave->w)
+      {
+       x -= cave->w;
+       y++;
+      }
+
+      // lineshifting does not fix the y coordinates.
+      // if out of bounds, element will not be displayed.
+      // if such an object appeared in the c64 game, well, it was a buffer overrun.
+    }
+    else
+    {
+      // non lineshifting: changing x does not change y coordinate.
+      while (x < 0)
+       x += cave->w;
+
+      while (x >= cave->w)
+       x -= cave->w;
+
+      // after that, fix y coordinate
+      while (y < 0)
+       y += cave->h;
+
+      while (y >= cave->h)
+       y -= cave->h;
+    }
+  }
+
+  // if the above wraparound code fixed the coordinates, this will always be true.
+  // but see the above comment for lineshifting y coordinate
+  if (x >= 0 && x < cave->w && y >= 0 && y < cave->h)
+  {
+    cave->map[y][x] = element;
+    cave->objects_order[y][x] = (void *)order;
+  }
+}
+
+GdElement gd_cave_get_rc(const GdCave *cave, int x, int y)
+{
+  // always fix coordinates as if cave was wraparound.
+
+  // fix x coordinate
+  if (cave->lineshift)
+  {
+    // fit x coordinate within range, with correcting y at the same time
+    while (x < 0)
+    {
+      x += cave->w;    // out of bounds on the left...
+      y--;             // previous row
+    }
+    while (x >= cave->w)
+    {
+      x -= cave->w;
+      y++;
+    }
+  }
+  else
+  {
+    // non lineshifting: changing x does not change y coordinate.
+    while (x < 0)
+      x += cave->w;
+
+    while (x >= cave->w)
+      x -= cave->w;
+  }
+
+  // after that, fix y coordinate
+  while (y < 0)
+    y += cave->h;
+
+  while (y >= cave->h)
+    y -= cave->h;
+
+  return cave->map[y][x];
+}
+
+unsigned int gd_c64_random(GdC64RandomGenerator *rand)
+{
+  unsigned int temp_rand_1, temp_rand_2, carry, result;
+
+  temp_rand_1 = (rand->rand_seed_1 & 0x0001) << 7;
+  temp_rand_2 = (rand->rand_seed_2 >> 1) & 0x007F;
+  result = (rand->rand_seed_2) + ((rand->rand_seed_2 & 0x0001) << 7);
+  carry = (result >> 8);
+  result = result & 0x00FF;
+  result = result + carry + 0x13;
+  carry = (result >> 8);
+  rand->rand_seed_2 = result & 0x00FF;
+  result = rand->rand_seed_1 + carry + temp_rand_1;
+  carry = (result >> 8);
+  result = result & 0x00FF;
+  result = result + carry + temp_rand_2;
+  rand->rand_seed_1 = result & 0x00FF;
+
+  return rand->rand_seed_1;
+}
+
+/*
+  C64 BD predictable random number generator.
+  Used to load the original caves imported from c64 files.
+  Also by the predictable slime.
+*/
+unsigned int gd_cave_c64_random(GdCave *cave)
+{
+  return gd_c64_random(&cave->c64_rand);
+}
+
+void gd_c64_random_set_seed(GdC64RandomGenerator *rand, int seed1, int seed2)
+{
+  rand->rand_seed_1 = seed1;
+  rand->rand_seed_2 = seed2;
+}
+
+void gd_cave_c64_random_set_seed(GdCave *cave, int seed1, int seed2)
+{
+  gd_c64_random_set_seed(&cave->c64_rand, seed1, seed2);
+}
+
+/*
+  select random colors for a given cave.
+  this function will select colors so that they should look somewhat nice; for example
+  brick walls won't be the darkest color, for example.
+*/
+static inline void swap(int *i1, int *i2)
+{
+  int t = *i1;
+
+  *i1 = *i2;
+  *i2 = t;
+}
+
+void gd_cave_set_random_c64_colors(GdCave *cave)
+{
+  const int bright_colors[] = { 1, 3, 7 };
+  const int dark_colors[] = { 2, 6, 8, 9, 11 };
+
+  // always black
+  cave->colorb = gd_c64_color(0);
+  cave->color0 = gd_c64_color(0);
+
+  // choose some bright color for brick
+  cave->color3 = gd_c64_color(bright_colors[gd_random_int_range(0, ARRAY_SIZE(bright_colors))]);
+
+  // choose a dark color for dirt, but should not be == color of brick
+  do
+  {
+    cave->color1 = gd_c64_color(dark_colors[gd_random_int_range(0, ARRAY_SIZE(dark_colors))]);
+  }
+  while (cave->color1 == cave->color3);    // so it is not the same as color 1
+
+  // choose any but black for steel wall, but should not be == brick or dirt
+  do
+  {
+    // between 1 and 15 - do not use black for this.
+    cave->color2 = gd_c64_color(gd_random_int_range(1, 16));
+  }
+  while (cave->color1 == cave->color2 || cave->color2 == cave->color3);    // so colors are not the same
+
+  // copy amoeba and slime color
+  cave->color4 = cave->color3;
+  cave->color5 = cave->color1;
+}
+
+static void cave_set_random_indexed_colors(GdCave *cave, GdColor (*color_indexer_func) (int, int))
+{
+  int hue = gd_random_int_range(0, 15);
+  int hue_spread = gd_random_int_range(1, 6);    // 1..5
+
+  // we only use 0..6, as saturation 15 is too bright (almost always white)
+  // also, saturation 0..1..2 is too dark. the color0=black is there for dark.
+  // so this is also 1..5. when hue spread is low, brightness spread is high
+  int bri_spread = 6 - hue_spread;
+  int bri1 = 8, bri2 = 8 - bri_spread, bri3 = 8 + bri_spread;
+
+  // there are 15 valid choices for hue, so we do a %15
+  int col1 = hue, col2 = (hue + hue_spread + 15) % 15, col3 = (hue - hue_spread + 15) % 15;
+
+  // this makes up a random color, and selects a color triad by hue+5 and hue+10.
+  // also creates a random saturation.
+  // color of brick is 8+sat, so it is always a bright color.
+  // another two are 8-sat and 8.
+  // order of colors is also changed randomly.
+  if (gd_random_boolean())    swap(&bri1, &bri2);
+
+  // we do not touch bri3 (8+sat), as it should be a bright color
+  if (gd_random_boolean())    swap(&col1, &col2);
+  if (gd_random_boolean())    swap(&col2, &col3);
+  if (gd_random_boolean())    swap(&col1, &col3);
+
+  cave->colorb = color_indexer_func(0, 0);
+  cave->color0 = color_indexer_func(0, 0);
+  cave->color1 = color_indexer_func(col1 + 1, bri1);
+  cave->color2 = color_indexer_func(col2 + 1, bri2);
+  cave->color3 = color_indexer_func(col3 + 1, bri3);
+  // amoeba and slime are different
+  // some green thing
+  cave->color4 = color_indexer_func(gd_random_int_range(11, 13), gd_random_int_range(6, 12));
+  // some blueish thing
+  cave->color5 = color_indexer_func(gd_random_int_range(7, 10),  gd_random_int_range(0, 6));
+}
+
+static void gd_cave_set_random_atari_colors(GdCave *cave)
+{
+  cave_set_random_indexed_colors(cave, gd_atari_color_huesat);
+}
+
+static void gd_cave_set_random_c64dtv_colors(GdCave *cave)
+{
+  cave_set_random_indexed_colors(cave, gd_c64dtv_color_huesat);
+}
+
+static inline void swapd(double *i1, double *i2)
+{
+  double t = *i1;
+
+  *i1 = *i2;
+  *i2 = t;
+}
+
+static void gd_cave_set_random_rgb_colors(GdCave *cave)
+{
+  const double hue_max = 10.0 / 30.0;
+  // any hue allowed
+  double hue = gd_random_double();
+  // hue 360 degress=1.  hue spread is min. 24 degrees, max 120 degrees (1/3)
+  double hue_spread = gd_random_double_range(2.0 / 30.0, hue_max);
+  double h1 = hue, h2 = hue + hue_spread, h3 = hue + 2 * hue_spread;
+  double v1, v2, v3;
+  double s1, s2, s3;
+
+  if (gd_random_boolean())
+  {
+    // when hue spread is low, brightness(saturation) spread is high
+    // this formula gives a number (x) between 0.1 and 0.4,
+    // which will be 0.5-x and 0.5+x, so the range is 0.1->0.9
+    double spread = 0.1 + 0.3 * (1 - hue_spread / hue_max);
+    v1 = 0.6;                // brightness variation, too
+    v2 = 0.7;
+    v3 = 0.8;
+    s1 = 0.5;                // saturation is different
+    s2 = 0.5 - spread;
+    s3 = 0.5 + spread;
+  }
+  else
+  {
+    // when hue spread is low, brightness(saturation) spread is high
+    // this formula gives a number (x) between 0.1 and 0.25,
+    // which will be 0.5+x and 0.5+2x, so the range is 0.5->0.9
+    double spread = 0.1 + 0.15 * (1 - hue_spread / hue_max);
+    v1 = 0.5;                // brightness is different
+    v2 = 0.5 + spread;
+    v3 = 0.5 + 2 * spread;
+    s1 = 0.7;                // saturation is same - a not fully saturated one
+    s2 = 0.8;
+    s3 = 0.9;
+  }
+
+  // randomly change values, but do not touch v3, as cave->color3 should be a bright color
+  if (gd_random_boolean())    swapd(&v1, &v2);
+
+  // randomly change hues and saturations
+  if (gd_random_boolean())    swapd(&h1, &h2);
+  if (gd_random_boolean())    swapd(&h2, &h3);
+  if (gd_random_boolean())    swapd(&h1, &h3);
+  if (gd_random_boolean())    swapd(&s1, &s2);
+  if (gd_random_boolean())    swapd(&s2, &s3);
+  if (gd_random_boolean())    swapd(&s1, &s3);
+
+  h1 = h1 * 360.0;
+  h2 = h2 * 360.0;
+  h3 = h3 * 360.0;
+
+  cave->colorb = gd_color_get_from_hsv(0, 0, 0);
+  cave->color0 = gd_color_get_from_hsv(0, 0, 0);       // black for background
+  cave->color1 = gd_color_get_from_hsv(h1, s1, v1);    // dirt
+  cave->color2 = gd_color_get_from_hsv(h2, s2, v2);    // steel
+  cave->color3 = gd_color_get_from_hsv(h3, s3, v3);    // brick
+  // green(120+-20) with the saturation and brightness of brick
+  cave->color4 = gd_color_get_from_hsv(gd_random_int_range(100, 140), s2, v2);
+  // blue(240+-20) with saturation and brightness of dirt
+  cave->color5 = gd_color_get_from_hsv(gd_random_int_range(220, 260), s1, v1);
+}
+
+void gd_cave_set_random_colors(GdCave *cave, GdColorType type)
+{
+  switch (type)
+  {
+    case GD_COLOR_TYPE_RGB:
+      gd_cave_set_random_rgb_colors(cave);
+      break;
+
+    case GD_COLOR_TYPE_C64:
+      gd_cave_set_random_c64_colors(cave);
+      break;
+
+    case GD_COLOR_TYPE_C64DTV:
+      gd_cave_set_random_c64dtv_colors(cave);
+      break;
+
+    case GD_COLOR_TYPE_ATARI:
+      gd_cave_set_random_atari_colors(cave);
+      break;
+
+    default:
+      break;
+  }
+}
+
+/*
+  shrink cave
+  if last line or last row is just steel wall (or (invisible) outbox).
+  used after loading a game for playing.
+  after this, ew and eh will contain the effective width and height.
+*/
+void gd_cave_auto_shrink(GdCave *cave)
+{
+
+  int x, y;
+  enum
+  {
+    STEEL_ONLY,
+    STEEL_OR_OTHER,
+    NO_SHRINK
+  }
+  empty;
+
+  // set to maximum size, then try to shrink
+  cave->x1 = 0;
+  cave->y1 = 0;
+  cave->x2 = cave->w - 1;
+  cave->y2 = cave->h - 1;
+
+  // search for empty, steel-wall-only last rows.
+  // clear all lines, which are only steel wall.
+  // and clear only one line, which is steel wall, but also has a player or an outbox.
+  empty = STEEL_ONLY;
+
+  do
+  {
+    for (y = cave->y2 - 1; y <= cave->y2; y++)
+    {
+      for (x = cave->x1; x <= cave->x2; x++)
+      {
+       switch (gd_cave_get_rc (cave, x, y))
+       {
+         // if steels only, this is to be deleted.
+         case O_STEEL:
+           break;
+
+         case O_PRE_OUTBOX:
+         case O_PRE_INVIS_OUTBOX:
+         case O_INBOX:
+           if (empty == STEEL_OR_OTHER)
+             empty = NO_SHRINK;
+
+           // if this, delete only this one, and exit.
+           if (empty == STEEL_ONLY)
+             empty = STEEL_OR_OTHER;
+           break;
+
+         default:
+           // anything else, that should be left in the cave.
+           empty = NO_SHRINK;
+           break;
+       }
+      }
+    }
+
+    // shrink if full steel or steel and player/outbox.
+    if (empty != NO_SHRINK)
+      cave->y2--;            // one row shorter
+  }
+  while (empty == STEEL_ONLY);    // if found just steels, repeat.
+
+  // search for empty, steel-wall-only first rows.
+  empty = STEEL_ONLY;
+
+  do
+  {
+    for (y = cave->y1; y <= cave->y1 + 1; y++)
+    {
+      for (x = cave->x1; x <= cave->x2; x++)
+      {
+       switch (gd_cave_get_rc (cave, x, y))
+       {
+         case O_STEEL:
+           break;
+
+         case O_PRE_OUTBOX:
+         case O_PRE_INVIS_OUTBOX:
+         case O_INBOX:
+           // shrink only lines, which have only ONE player or outbox.
+           // this is for bd4 intermission 2, for example.
+           if (empty == STEEL_OR_OTHER)
+             empty = NO_SHRINK;
+           if (empty == STEEL_ONLY)
+             empty = STEEL_OR_OTHER;
+           break;
+
+         default:
+           empty = NO_SHRINK;
+           break;
+       }
+      }
+    }
+
+    if (empty != NO_SHRINK)
+      cave->y1++;
+  }
+  while (empty == STEEL_ONLY);    // if found one, repeat.
+
+  // empty last columns.
+  empty = STEEL_ONLY;
+
+  do
+  {
+    for (y = cave->y1; y <= cave->y2; y++)
+    {
+      for (x = cave->x2 - 1; x <= cave->x2; x++)
+      {
+       switch (gd_cave_get_rc (cave, x, y))
+       {
+         case O_STEEL:
+           break;
+
+         case O_PRE_OUTBOX:
+         case O_PRE_INVIS_OUTBOX:
+         case O_INBOX:
+           if (empty == STEEL_OR_OTHER)
+             empty = NO_SHRINK;
+           if (empty == STEEL_ONLY)
+             empty = STEEL_OR_OTHER;
+           break;
+
+         default:
+           empty = NO_SHRINK;
+           break;
+       }
+      }
+    }
+
+    // just remember that one column shorter.
+    // free will know the size of memchunk, no need to realloc!
+    if (empty != NO_SHRINK)
+      cave->x2--;
+  }
+  while (empty == STEEL_ONLY);    // if found one, repeat.
+
+  // empty first columns.
+  empty = STEEL_ONLY;
+
+  do
+  {
+    for (y = cave->y1; y <= cave->y2; y++)
+    {
+      for (x = cave->x1; x <= cave->x1 + 1; x++)
+      {
+       switch (gd_cave_get_rc (cave, x, y))
+       {
+         case O_STEEL:
+           break;
+
+         case O_PRE_OUTBOX:
+         case O_PRE_INVIS_OUTBOX:
+         case O_INBOX:
+           if (empty == STEEL_OR_OTHER)
+             empty = NO_SHRINK;
+           if (empty == STEEL_ONLY)
+             empty = STEEL_OR_OTHER;
+           break;
+
+         default:
+           empty = NO_SHRINK;
+           break;
+       }
+      }
+    }
+
+    if (empty != NO_SHRINK)
+      cave->x1++;
+  }
+  while (empty == STEEL_ONLY);    // if found one, repeat.
+}
+
+/*
+  check if cave visible part coordinates
+  are outside cave sizes, or not in the right order.
+  correct them if needed.
+*/
+void gd_cave_correct_visible_size(GdCave *cave)
+{
+  // change visible coordinates if they do not point to upperleft and lowerright
+  if (cave->x2 < cave->x1)
+  {
+    int t = cave->x2;
+    cave->x2 = cave->x1;
+    cave->x1 = t;
+  }
+
+  if (cave->y2 < cave->y1)
+  {
+    int t = cave->y2;
+    cave->y2 = cave->y1;
+    cave->y1 = t;
+  }
+
+  if (cave->x1 < 0)
+    cave->x1 = 0;
+
+  if (cave->y1 < 0)
+    cave->y1 = 0;
+
+  if (cave->x2 > cave->w - 1)
+    cave->x2 = cave->w - 1;
+
+  if (cave->y2 > cave->h - 1)
+    cave->y2 = cave->h - 1;
+}
+
+/*
+  bd1 and similar engines had animation bits in cave data, to set which elements to animate
+  (firefly, butterfly, amoeba).
+  animating an element also caused some delay each frame; according to my measurements,
+  around 2.6 ms/element.
+*/
+static void cave_set_ckdelay_extra_for_animation(GdCave *cave)
+{
+  int x, y;
+  boolean has_amoeba = FALSE, has_firefly = FALSE, has_butterfly = FALSE;
+
+  for (y = 0; y < cave->h; y++)
+  {
+    for (x = 0; x < cave->w; x++)
+    {
+      switch (cave->map[y][x] & ~SCANNED)
+      {
+       case O_FIREFLY_1:
+       case O_FIREFLY_2:
+       case O_FIREFLY_3:
+       case O_FIREFLY_4:
+         has_firefly = TRUE;
+         break;
+
+       case O_BUTTER_1:
+       case O_BUTTER_2:
+       case O_BUTTER_3:
+       case O_BUTTER_4:
+         has_butterfly = TRUE;
+         break;
+
+       case O_AMOEBA:
+         has_amoeba = TRUE;
+         break;
+      }
+    }
+  }
+
+  cave->ckdelay_extra_for_animation = 0;
+  if (has_amoeba)
+    cave->ckdelay_extra_for_animation += 2600;
+  if (has_firefly)
+    cave->ckdelay_extra_for_animation += 2600;
+  if (has_butterfly)
+    cave->ckdelay_extra_for_animation += 2600;
+  if (has_amoeba)
+    cave->ckdelay_extra_for_animation += 2600;
+}
+
+// do some init - setup some cave variables before the game.
+void gd_cave_setup_for_game(GdCave *cave)
+{
+  int x, y;
+
+  cave_set_ckdelay_extra_for_animation(cave);
+
+  // find the player which will be the one to scroll to at the beginning of the game
+  // (before the player's birth)
+  if (cave->active_is_first_found)
+  {
+    // uppermost player is active
+    for (y = cave->h - 1; y >= 0; y--)
+    { 
+     for (x = cave->w - 1; x >= 0; x--)
+     {
+       if (cave->map[y][x] == O_INBOX)
+       {
+         cave->player_x = x;
+         cave->player_y = y;
+       }
+     }
+    }
+  }
+  else
+  {
+    // lowermost player is active
+    for (y = 0; y < cave->h; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       if (cave->map[y][x] == O_INBOX)
+       {
+         cave->player_x = x;
+         cave->player_y = y;
+       }
+      }
+    }
+  }
+
+  // select number of milliseconds (for pal and ntsc)
+  cave->timing_factor = cave->pal_timing ? 1200 : 1000;
+
+  cave->time                   *= cave->timing_factor;
+  cave->magic_wall_time                *= cave->timing_factor;
+  cave->amoeba_time            *= cave->timing_factor;
+  cave->amoeba_2_time          *= cave->timing_factor;
+  cave->hatching_delay_time    *= cave->timing_factor;
+
+  if (cave->hammered_walls_reappear)
+    cave->hammered_reappear = gd_cave_map_new(cave, int);
+}
+
+// cave diamonds needed can be set to n<=0.
+// if so, count the diamonds at the time of the hatching, and decrement that value from
+// the number of diamonds found.
+// of course, this function is to be called from the cave engine, at the exact time of hatching.
+void gd_cave_count_diamonds(GdCave *cave)
+{
+  int x, y;
+
+  // if automatically counting diamonds. if this was negative,
+  // the sum will be this less than the number of all the diamonds in the cave
+  if (cave->diamonds_needed <= 0)
+  {
+    for (y = 0; y < cave->h; y++)
+      for (x = 0; x < cave->w; x++)
+       if (cave->map[y][x] == O_DIAMOND)
+         cave->diamonds_needed++;
+
+    // if still below zero, let this be 0, so gate will be open immediately
+    if (cave->diamonds_needed < 0)
+      cave->diamonds_needed = 0;
+  }
+}
+
+/*
+  takes a cave and a gfx buffer, and fills the buffer with cell indexes.
+  the indexes might change if bonus life flash is active (small lines in
+  "SPACE" cells),
+  for the paused state (which is used in gdash but not in sdash) - yellowish
+  color.
+  also one can select the animation frame (0..7) to draw the cave on. so the
+  caller manages
+  increasing that.
+
+  if a cell is changed, it is flagged with GD_REDRAW; the flag can be cleared
+  by the caller.
+*/
+void gd_drawcave_game(const GdCave *cave,
+                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
+                     boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox)
+{
+  static int player_blinking = 0;
+  static int player_tapping = 0;
+  int elemmapping[O_MAX_ALL];
+  int elemdrawing[O_MAX_ALL];
+  int x, y, map, draw;
+
+  if (cave->last_direction)
+  {
+    // he is moving, so stop blinking and tapping.
+    player_blinking = 0;
+    player_tapping = 0;
+  }
+  else
+  {
+    // he is idle, so animations can be done.
+    if (animcycle == 0)
+    {
+      // blinking and tapping is started at the beginning of animation sequences.
+      // 1/4 chance of blinking, every sequence.
+      player_blinking = gd_random_int_range(0, 4) == 0;
+
+      // 1/16 chance of starting or stopping tapping.
+      if (gd_random_int_range(0, 16) == 0)
+       player_tapping = !player_tapping;
+    }
+  }
+
+  for (x = 0; x < O_MAX_ALL; x++)
+  {
+    elemmapping[x] = x;
+    elemdrawing[x] = gd_elements[x].image_game;
+  }
+
+  if (bonus_life_flash)
+  {
+    elemmapping[O_SPACE] = O_FAKE_BONUS;
+    elemdrawing[O_SPACE] = gd_elements[O_FAKE_BONUS].image_game;
+  }
+
+  elemmapping[O_MAGIC_WALL] = (cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK);
+  elemdrawing[O_MAGIC_WALL] = gd_elements[cave->magic_wall_state == GD_MW_ACTIVE ? O_MAGIC_WALL : O_BRICK].image_game;
+
+  elemmapping[O_CREATURE_SWITCH] = (cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH);
+  elemdrawing[O_CREATURE_SWITCH] = gd_elements[cave->creatures_backwards ? O_CREATURE_SWITCH_ON : O_CREATURE_SWITCH].image_game;
+
+  elemmapping[O_EXPANDING_WALL_SWITCH] = (cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ);
+  elemdrawing[O_EXPANDING_WALL_SWITCH] = gd_elements[cave->expanding_wall_changed ? O_EXPANDING_WALL_SWITCH_VERT : O_EXPANDING_WALL_SWITCH_HORIZ].image_game;
+
+  elemmapping[O_GRAVITY_SWITCH] = (cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH);
+  elemdrawing[O_GRAVITY_SWITCH] = gd_elements[cave->gravity_switch_active ? O_GRAVITY_SWITCH_ACTIVE : O_GRAVITY_SWITCH].image_game;
+
+  elemmapping[O_REPLICATOR_SWITCH] = (cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF);
+  elemdrawing[O_REPLICATOR_SWITCH] = gd_elements[cave->replicators_active ? O_REPLICATOR_SWITCH_ON : O_REPLICATOR_SWITCH_OFF].image_game;
+
+  if (cave->replicators_active)
+    // if the replicators are active, animate them.
+    elemmapping[O_REPLICATOR] = O_REPLICATOR_ACTIVE;
+
+  if (!cave->replicators_active)
+    // if the replicators are inactive, do not animate them.
+    elemdrawing[O_REPLICATOR] = ABS(elemdrawing[O_REPLICATOR]);
+
+  elemmapping[O_CONVEYOR_SWITCH] = (cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF);
+  elemdrawing[O_CONVEYOR_SWITCH] = gd_elements[cave->conveyor_belts_active ? O_CONVEYOR_SWITCH_ON : O_CONVEYOR_SWITCH_OFF].image_game;
+
+  if (cave->conveyor_belts_direction_changed)
+  {
+    // if direction is changed, animation is changed.
+    int temp;
+
+    elemmapping[O_CONVEYOR_LEFT] = O_CONVEYOR_RIGHT;
+    elemmapping[O_CONVEYOR_RIGHT] = O_CONVEYOR_LEFT;
+
+    temp = elemdrawing[O_CONVEYOR_LEFT];
+    elemdrawing[O_CONVEYOR_LEFT] = elemdrawing[O_CONVEYOR_RIGHT];
+    elemdrawing[O_CONVEYOR_RIGHT] = temp;
+
+    elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_CHANGED;
+    elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_CHANGED].image_game;
+  }
+  else
+  {
+    elemmapping[O_CONVEYOR_DIR_SWITCH] = O_CONVEYOR_DIR_NORMAL;
+    elemdrawing[O_CONVEYOR_DIR_SWITCH] = gd_elements[O_CONVEYOR_DIR_NORMAL].image_game;
+  }
+
+  if (cave->conveyor_belts_active)
+  {
+    // keep potentially changed direction
+    int offset = (O_CONVEYOR_LEFT_ACTIVE - O_CONVEYOR_LEFT);
+
+    // if they are running, animate them.
+    elemmapping[O_CONVEYOR_LEFT]  += offset;
+    elemmapping[O_CONVEYOR_RIGHT] += offset;
+  }
+  if (!cave->conveyor_belts_active)
+  {
+    // if they are not running, do not animate them.
+    elemdrawing[O_CONVEYOR_LEFT] = ABS(elemdrawing[O_CONVEYOR_LEFT]);
+    elemdrawing[O_CONVEYOR_RIGHT] = ABS(elemdrawing[O_CONVEYOR_RIGHT]);
+  }
+
+  if (animcycle & 2)
+  {
+    // also a hack, like biter_switch
+    elemdrawing[O_PNEUMATIC_ACTIVE_LEFT]  += 2;
+    elemdrawing[O_PNEUMATIC_ACTIVE_RIGHT] += 2;
+    elemdrawing[O_PLAYER_PNEUMATIC_LEFT]  += 2;
+    elemdrawing[O_PLAYER_PNEUMATIC_RIGHT] += 2;
+  }
+
+  if ((cave->last_direction) == GD_MV_STILL)
+  {
+    // player is idle.
+    if (player_blinking && player_tapping)
+    {
+      map = O_PLAYER_TAP_BLINK;
+      draw = gd_elements[O_PLAYER_TAP_BLINK].image_game;
+    }
+    else if (player_blinking)
+    {
+      map = O_PLAYER_BLINK;
+      draw = gd_elements[O_PLAYER_BLINK].image_game;
+    }
+    else if (player_tapping)
+    {
+      map = O_PLAYER_TAP;
+      draw = gd_elements[O_PLAYER_TAP].image_game;
+    }
+    else
+    {
+      map = O_PLAYER;
+      draw = gd_elements[O_PLAYER].image_game;
+    }
+  }
+  else if (cave->last_direction == GD_MV_UP && use_bd_up_down_graphics())
+  {
+    map = O_PLAYER_UP;
+    draw = gd_elements[O_PLAYER_UP].image_game;
+  }
+  else if (cave->last_direction == GD_MV_DOWN && use_bd_up_down_graphics())
+  {
+    map = O_PLAYER_DOWN;
+    draw = gd_elements[O_PLAYER_DOWN].image_game;
+  }
+  else if (cave->last_horizontal_direction == GD_MV_LEFT)
+  {
+    map = O_PLAYER_LEFT;
+    draw = gd_elements[O_PLAYER_LEFT].image_game;
+  }
+  else
+  {
+    // of course this is GD_MV_RIGHT.
+    map = O_PLAYER_RIGHT;
+    draw = gd_elements[O_PLAYER_RIGHT].image_game;
+  }
+
+  elemmapping[O_PLAYER] = map;
+  elemmapping[O_PLAYER_GLUED] = map;
+
+  elemdrawing[O_PLAYER] = draw;
+  elemdrawing[O_PLAYER_GLUED] = draw;
+
+  // player with bomb/rocketlauncher does not blink or tap - no graphics drawn for that.
+  // running is drawn using w/o bomb/rocketlauncher cells */
+  if (cave->last_direction != GD_MV_STILL)
+  {
+    elemmapping[O_PLAYER_BOMB] = map;
+    elemdrawing[O_PLAYER_BOMB] = draw;
+
+    elemmapping[O_PLAYER_ROCKET_LAUNCHER] = map;
+    elemdrawing[O_PLAYER_ROCKET_LAUNCHER] = draw;
+  }
+
+  elemmapping[O_INBOX] = (cave->inbox_flash_toggle ? O_INBOX_OPEN : O_INBOX_CLOSED);
+  elemdrawing[O_INBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
+
+  elemmapping[O_OUTBOX] = (cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED);
+  elemdrawing[O_OUTBOX] = gd_elements[cave->inbox_flash_toggle ? O_OUTBOX_OPEN : O_OUTBOX_CLOSED].image_game;
+
+  // hack, not fit into gd_elements
+  elemmapping[O_BITER_SWITCH] = O_BITER_SWITCH_1 + cave->biter_delay_frame;
+  // hack, not fit into gd_elements
+  elemdrawing[O_BITER_SWITCH] = gd_elements[O_BITER_SWITCH].image_game + cave->biter_delay_frame;
+
+  // visual effects
+  elemmapping[O_DIRT] = cave->dirt_looks_like;
+  elemmapping[O_EXPANDING_WALL] = cave->expanding_wall_looks_like;
+  elemmapping[O_V_EXPANDING_WALL] = cave->expanding_wall_looks_like;
+  elemmapping[O_H_EXPANDING_WALL] = cave->expanding_wall_looks_like;
+  elemmapping[O_AMOEBA_2] = cave->amoeba_2_looks_like;
+
+  // visual effects
+  elemdrawing[O_DIRT] = elemdrawing[cave->dirt_looks_like];
+  elemdrawing[O_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
+  elemdrawing[O_V_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
+  elemdrawing[O_H_EXPANDING_WALL] = elemdrawing[cave->expanding_wall_looks_like];
+  elemdrawing[O_AMOEBA_2] = elemdrawing[cave->amoeba_2_looks_like];
+
+  // change only graphically
+  if (hate_invisible_outbox)
+  {
+    elemmapping[O_PRE_INVIS_OUTBOX] = elemmapping[O_PRE_OUTBOX];
+    elemmapping[O_INVIS_OUTBOX] = elemmapping[O_OUTBOX];
+  }
+
+  if (hate_invisible_outbox)
+  {
+    elemdrawing[O_PRE_INVIS_OUTBOX] = elemdrawing[O_PRE_OUTBOX];
+    elemdrawing[O_INVIS_OUTBOX] = elemdrawing[O_OUTBOX];
+  }
+
+  for (y = cave->y1; y <= cave->y2; y++)
+  {
+    for (x = cave->x1; x <= cave->x2; x++)
+    {
+      GdElement actual = cave->map[y][x];
+
+      // if covered, real element is not important
+      if (actual & COVERED)
+       map = O_COVERED;
+      else
+       map = elemmapping[actual];
+
+      // if covered, real element is not important
+      if (actual & COVERED)
+       draw = gd_elements[O_COVERED].image_game;
+      else
+       draw = elemdrawing[actual];
+
+      // draw special graphics if player is pushing something
+      if (use_bd_pushing_graphics() &&
+         (cave->last_direction == GD_MV_LEFT || cave->last_direction == GD_MV_RIGHT) &&
+         is_player(cave, x, y) && can_be_pushed_dir(cave, x, y, cave->last_direction))
+      {
+       // special check needed when smooth game element movements selected in setup menu:
+       // last element must either be player (before pushing) or pushable element (while pushing)
+       // (extra check needed to prevent pushing animation when moving towards pushable element)
+       if (!use_bd_smooth_movements() || last_element_buffer[y][x] != O_SPACE)
+       {
+         if (cave->last_direction == GD_MV_LEFT)
+           map = O_PLAYER_PUSH_LEFT;
+         else
+           map = O_PLAYER_PUSH_RIGHT;
+
+         if (cave->last_direction == GD_MV_LEFT)
+           draw = elemdrawing[O_PLAYER_PUSH_LEFT];
+         else
+           draw = elemdrawing[O_PLAYER_PUSH_RIGHT];
+       }
+      }
+
+      // if negative, animated.
+      if (draw < 0)
+       draw = -draw + animcycle;
+
+      // flash
+      if (cave->gate_open_flash)
+       draw += GD_NUM_OF_CELLS;
+
+      // set to buffer, with caching
+      if (element_buffer[y][x] != map)
+       element_buffer[y][x] = map;
+
+      if (gfx_buffer[y][x] != draw)
+       gfx_buffer[y][x] = draw | GD_REDRAW;
+    }
+  }
+}
+
+/*
+  cave time is rounded _UP_ to seconds. so at the exact moment when it
+  changes from
+  2sec remaining to 1sec remaining, the player has exactly one second.
+  when it changes
+  to zero, it is the exact moment of timeout.
+
+  internal time is milliseconds (or 1200 milliseconds for pal timing).
+*/
+int gd_cave_time_show(const GdCave *cave, int internal_time)
+{
+  return (internal_time + cave->timing_factor - 1) / cave->timing_factor;
+}
+
+GdReplay *gd_replay_new(void)
+{
+  GdReplay *rep;
+
+  rep = checked_calloc(sizeof(GdReplay));
+  rep->movements = checked_calloc(sizeof(GdReplayMovements));
+
+  return rep;
+}
+
+GdReplay *gd_replay_new_from_replay(GdReplay *orig)
+{
+  GdReplay *rep;
+
+  rep = get_memcpy(orig, sizeof(GdReplay));
+
+  // replicate dynamic data
+  rep->comment = getStringCopy(orig->comment);
+  rep->movements = get_memcpy(orig->movements, sizeof(GdReplayMovements));
+
+  return rep;
+}
+
+void gd_replay_free(GdReplay *replay)
+{
+  checked_free(replay->movements);
+  checked_free(replay->comment);
+  free(replay);
+}
+
+// store movement in a replay
+void gd_replay_store_movement(GdReplay *replay, GdDirection player_move,
+                             boolean player_fire, boolean suicide)
+{
+  byte data[1];
+
+  data[0] = ((player_move) |
+            (player_fire ? GD_REPLAY_FIRE_MASK : 0) |
+            (suicide ? GD_REPLAY_SUICIDE_MASK : 0));
+
+  if (replay->movements->len < MAX_REPLAY_LEN)
+  {
+    replay->movements->data[replay->movements->len++] = data[0];
+
+    if (replay->movements->len == MAX_REPLAY_LEN)
+      Warn("BD replay truncated: size exceeds maximum replay size %d", MAX_REPLAY_LEN);
+  }
+}
+
+// calculate adler checksum for a rendered cave; this can be used for more caves.
+void gd_cave_adler_checksum_more(GdCave *cave, unsigned int *a, unsigned int *b)
+{
+  int x, y;
+
+  for (y = 0; y < cave->h; y++)
+    for (x = 0; x < cave->w; x++)
+    {
+      *a += gd_elements[cave->map[y][x]].character;
+      *b += *a;
+
+      *a %= 65521;
+      *b %= 65521;
+    }
+}
+
+// calculate adler checksum for a single rendered cave.
+unsigned int gd_cave_adler_checksum(GdCave *cave)
+{
+  unsigned int a = 1;
+  unsigned int b = 0;
+
+  gd_cave_adler_checksum_more(cave, &a, &b);
+  return (b << 16) + a;
+}
+
+boolean gd_cave_has_levels(GdCave *cave)
+{
+  GdCave c = *cave;
+  int *cave_level_value[] =
+  {
+    c.level_diamonds,
+    c.level_speed,
+    c.level_ckdelay,
+    c.level_time,
+    c.level_magic_wall_time,
+    c.level_amoeba_time,
+    c.level_amoeba_threshold,
+    c.level_amoeba_2_time,
+    c.level_amoeba_2_threshold,
+    c.level_slime_permeability,
+    c.level_slime_permeability_c64,
+    c.level_slime_seed_c64,
+    c.level_hatching_delay_frame,
+    c.level_hatching_delay_time,
+    c.level_bonus_time,
+    c.level_penalty_time,
+
+    NULL
+  };
+  int i, j;
+
+  for (i = 0; cave_level_value[i] != NULL; i++)
+    for (j = 1; j < 5; j++)
+      if (cave_level_value[i][j] != cave_level_value[i][0])
+       return TRUE;
+
+  for (j = 1; j < 5; j++)
+    if (cave->level_rand[j] != j &&
+       cave->level_rand[j - 1] != j - 1 &&
+       cave->level_rand[j] != cave->level_rand[0])
+      return TRUE;
+
+  for (j = 1; j < 5; j++)
+    if (cave->level_timevalue[j] != j + 1 &&
+       cave->level_timevalue[j - 1] != j &&
+       cave->level_timevalue[j] != cave->level_timevalue[0])
+      return TRUE;
+
+  return FALSE;
+}
+
+boolean gd_caveset_has_levels(void)
+{
+  List *iter;
+
+  for (iter = gd_caveset; iter != NULL; iter = iter->next)
+    if (gd_cave_has_levels((GdCave *)iter->data))
+      return TRUE;
+
+  return FALSE;
+}
diff --git a/src/game_bd/bd_cave.h b/src/game_bd/bd_cave.h
new file mode 100644 (file)
index 0000000..1a85776
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVE_H
+#define BD_CAVE_H
+
+#include "bd_elements.h"
+#include "bd_colors.h"
+#include "bd_random.h"
+
+
+// ============================================================================
+// BIG STRUCT HANDLING
+// ============================================================================
+
+// possible types handled
+typedef enum _gd_type
+{
+  // not real types, only used by editor to build ui
+  GD_TAB,
+  GD_LABEL,
+
+  // gd types
+  GD_TYPE_STRING,              // static string, fixed array of characters
+  GD_TYPE_LONGSTRING,          // long string which has its own notebook page in the editor
+  GD_TYPE_INT,
+  GD_TYPE_RATIO,
+  GD_TYPE_ELEMENT,
+  GD_TYPE_BOOLEAN,
+  GD_TYPE_PROBABILITY,         // probabilities are stored in parts per million,
+                               // ie. *1E6, converted to int.
+  GD_TYPE_COLOR,
+  GD_TYPE_EFFECT,
+  GD_TYPE_DIRECTION,
+  GD_TYPE_SCHEDULING,
+} GdType;
+
+enum _gd_property_flags
+{
+  GD_ALWAYS_SAVE           = 1 << 0,
+  GD_DONT_SAVE             = 1 << 1,
+  GD_DONT_SHOW_IN_EDITOR   = 1 << 2,
+  GD_SHOW_LEVEL_LABEL      = 1 << 3,
+  GD_COMPATIBILITY_SETTING = 1 << 4,
+};
+
+typedef struct _gd_struct_descriptor
+{
+  char *identifier;            // bdcff identifier
+  GdType type;                 // data type
+  int flags;                   // flags for bdcff saving/loading
+  char *name;                  // name in editor
+  int offset;                  // byte offset in a GdCave structure. use the CAVE_OFFSET macro
+  int count;                   // size of array; usually 1, for non-arrays.
+  char *tooltip;               // tooltip text in editor
+  int min, max;                        // integers have minimum and maximum
+} GdStructDescriptor;
+
+typedef struct _gd_property_default
+{
+  int offset;                  // data offset (bytes) in a cave structure
+  int defval;                  // default value, converted to int. if type is a float, *1000000
+
+  int property_index;          // index in gd_cave_properties; created at runtime
+} GdPropertyDefault;
+
+
+void gd_struct_set_defaults_from_array(void *str, const GdStructDescriptor *properties, GdPropertyDefault *defaults);
+
+// these define the number of the cells in the png file
+#define GD_NUM_OF_CELLS_X      8
+#define GD_NUM_OF_CELLS_Y      51
+
+// +80: placeholder for cells which are rendered by the game;
+// for example diamond + arrow = falling diamond
+#define GD_NUM_OF_CELLS                (GD_NUM_OF_CELLS_X * GD_NUM_OF_CELLS_Y + 80)
+
+// maximum replay size (maximum seconds x game cycles per second)
+#define MAX_REPLAY_LEN         (10000 * FRAMES_PER_SECOND / 8)
+
+extern const GdColor gd_flash_color;
+extern const GdColor gd_select_color;
+
+enum _element_property
+{
+  E_P_SLOPED_LEFT,              // stones and diamonds roll down to left on this
+  E_P_SLOPED_RIGHT,             // stones and diamonds roll down to right on this
+  E_P_SLOPED_UP,
+  E_P_SLOPED_DOWN,
+  E_P_BLADDER_SLOPED,           // element act sloped also for the bladder
+
+  E_P_AMOEBA_CONSUMES,          // amoeba can eat this
+  E_P_DIRT,                     // it is dirt, or something similar (dirt2 or sloped dirt)
+  E_P_BLOWS_UP_FLIES,           // flies blow up, if they touch this
+  E_P_EXPLODES_BY_HIT,          // explodes if hit by a stone
+
+  E_P_EXPLOSION,                // set for every stage of every explosion.
+  E_P_EXPLOSION_FIRST_STAGE,    // set for first stage of every explosion.
+                               // helps slower/faster explosions changing
+
+  E_P_NON_EXPLODABLE,           // selfexplaining
+  E_P_CCW,                      // this creature has a default counterclockwise
+                               // rotation (for example, o_fire_1)
+  E_P_CAN_BE_HAMMERED,          // can be broken by pneumatic hammer
+  E_P_VISUAL_EFFECT,            // if the element can use a visual effect.
+                               // used to check consistency of the code
+  E_P_PLAYER,                   // easier to find out if it is a player element
+  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_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_FALLING,                  // falling
+  E_P_GROWING,                  // growing (element birth)
+};
+
+// properties
+#define P_SLOPED_LEFT                  (1 << E_P_SLOPED_LEFT)
+#define P_SLOPED_RIGHT                 (1 << E_P_SLOPED_RIGHT)
+#define P_SLOPED_UP                    (1 << E_P_SLOPED_UP)
+#define P_SLOPED_DOWN                  (1 << E_P_SLOPED_DOWN)
+
+// flag to say "any direction"
+#define P_SLOPED                       (P_SLOPED_LEFT  |               \
+                                        P_SLOPED_RIGHT |               \
+                                        P_SLOPED_UP    |               \
+                                        P_SLOPED_DOWN)
+
+#define P_BLADDER_SLOPED               (1 << E_P_BLADDER_SLOPED)
+
+#define P_AMOEBA_CONSUMES              (1 << E_P_AMOEBA_CONSUMES)
+#define P_DIRT                         (1 << E_P_DIRT)
+#define P_BLOWS_UP_FLIES               (1 << E_P_BLOWS_UP_FLIES)
+
+#define P_EXPLODES_BY_HIT              (1 << E_P_EXPLODES_BY_HIT)
+#define P_EXPLOSION                    (1 << E_P_EXPLOSION)
+#define P_EXPLOSION_FIRST_STAGE                (1 << E_P_EXPLOSION_FIRST_STAGE)
+
+#define P_NON_EXPLODABLE               (1 << E_P_NON_EXPLODABLE)
+#define P_CCW                          (1 << E_P_CCW)
+#define P_CAN_BE_HAMMERED              (1 << E_P_CAN_BE_HAMMERED)
+#define P_VISUAL_EFFECT                        (1 << E_P_VISUAL_EFFECT)
+#define P_PLAYER                       (1 << E_P_PLAYER)
+#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_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_FALLING                      (1 << E_P_FALLING)
+#define P_GROWING                      (1 << E_P_GROWING)
+
+// These are states of the magic wall.
+typedef enum _magic_wall_state
+{
+  GD_MW_DORMANT,                // Starting with this.
+  GD_MW_ACTIVE,                 // Boulder or diamond dropped into.
+  GD_MW_EXPIRED                 // Turned off after magic_wall_milling_time.
+} GdMagicWallState;
+
+// These are states of Player.
+typedef enum _player_state
+{
+  GD_PL_NOT_YET,                // Not yet living. Beginning of cave time.
+  GD_PL_LIVING,                 // Ok.
+  GD_PL_TIMEOUT,                // Time is up
+  GD_PL_DIED,                   // Died.
+  GD_PL_EXITED                  // Exited the cave, proceed to next one
+} GdPlayerState;
+
+// States of amoeba
+typedef enum _amoeba_state
+{
+  GD_AM_SLEEPING,               // sleeping - not yet let out.
+  GD_AM_AWAKE,                  // living, growing
+  GD_AM_TOO_BIG,                // grown too big, will convert to stones
+  GD_AM_ENCLOSED,               // enclosed, will convert to diamonds
+} GdAmoebaState;
+
+typedef enum _direction
+{
+  // not moving
+  GD_MV_STILL          = 0,
+  GD_MV_THIS           = 0,
+
+  // directions
+  GD_MV_UP             = 1,
+  GD_MV_UP_RIGHT       = 2,
+  GD_MV_RIGHT          = 3,
+  GD_MV_DOWN_RIGHT     = 4,
+  GD_MV_DOWN           = 5,
+  GD_MV_DOWN_LEFT      = 6,
+  GD_MV_LEFT           = 7,
+  GD_MV_UP_LEFT                = 8,
+
+  // to be able to type GD_MV_TWICE + GD_MV_DOWN, for example
+  GD_MV_TWICE          = 8,
+
+  // directions * 2
+  GD_MV_UP_2           = 9,
+  GD_MV_UP_RIGHT_2     = 10,
+  GD_MV_RIGHT_2                = 11,
+  GD_MV_DOWN_RIGHT_2   = 12,
+  GD_MV_DOWN_2         = 13,
+  GD_MV_DOWN_LEFT_2    = 14,
+  GD_MV_LEFT_2         = 15,
+  GD_MV_UP_LEFT_2      = 16,
+
+  GD_MV_MAX,
+} GdDirection;
+
+enum
+{
+  GD_REPLAY_MOVE_MASK   = 0x0f,
+  GD_REPLAY_FIRE_MASK   = 0x10,
+  GD_REPLAY_SUICIDE_MASK = 0x20,
+};
+
+
+// ELEMENTS DESCRIPTION
+typedef struct _elements
+{
+  GdElement element;            // element number. for example O_DIRT
+  char *name;                   // name in editor, for example "Dirt". some have
+                               // different names than their real engine meaning!
+  unsigned int properties;      // engine properties, like P_SLOPED or P_EXPLODES
+  char *filename;               // name in bdcff file, like "DIRT"
+  char character;               // character representation in bdcff file, like '.'
+  int image;                    // image in editor (index in cells.png)
+  int image_simple;             // image in editor (index in cells.png) (simple view / combo box)
+  int image_game;               // image for game. negative if animated
+  int ckdelay;                  // ckdelay ratio - how much time required for a c64 to
+                               // process this element - in microseconds.
+
+  char *lowercase_name;         // lowercase of translated name. for editor;
+                                // generated inside the game.
+  char character_new;           // character given automatically for elements which
+                               // don't have one defined in original bdcff description
+} GdElements;
+
+
+typedef char GdString[MAX_LINE_LEN];
+
+typedef struct _highscore
+{
+  GdString name;
+  int score;
+} GdHighScore;
+
+typedef struct _replay_movements
+{
+  unsigned char data[MAX_REPLAY_LEN];
+  unsigned int len;
+} GdReplayMovements;
+
+// maximum seed value for the cave random generator. should be smaller than a signed int.
+#define GD_CAVE_SEED_MAX       (1 << 30)
+
+typedef struct _gd_cave_replay
+{
+  int level;                    // replay for level n
+  unsigned int seed;            // seed the cave is to be rendered with
+  boolean saved;                // also store it in the saved bdcff
+  GdString recorded_with;       // recorded with - application name and version
+
+  GdString player_name;         // who played this
+  GdString date;                // when played
+  char *comment;                // some comments from the player
+
+  int score;                    // score collected
+  int duration;                 // number of seconds played
+  boolean success;              // successful playing of cave?
+  unsigned int checksum;        // checksum of the rendered cave.
+
+  boolean wrong_checksum;
+  GdReplayMovements *movements;
+  int current_playing_pos;
+} GdReplay;
+
+typedef enum _gd_scheduling
+{
+  GD_SCHEDULING_MILLISECONDS,
+  GD_SCHEDULING_BD1,
+  GD_SCHEDULING_BD2,
+  GD_SCHEDULING_PLCK,
+  GD_SCHEDULING_CRDR,
+  GD_SCHEDULING_BD1_ATARI,
+  GD_SCHEDULING_BD2_PLCK_ATARI,
+  GD_SCHEDULING_MAX
+} GdScheduling;
+
+typedef struct _gd_c64_random_generator
+{
+  int rand_seed_1, rand_seed_2;
+} GdC64RandomGenerator;
+
+// ----------------------------------------------------------------------------
+// Structure holding all data belonging to a cave.
+// ----------------------------------------------------------------------------
+
+#define GD_HIGHSCORE_NUM 20
+
+typedef struct _gd_cave
+{
+  // Defined by the editor. public data :)
+  GdString name;                        // name of cave
+  GdString description;                 // some words about the cave
+  GdString author;                      // author
+  GdString difficulty;                  // difficulty of the game, for info purposes
+  GdString www;                         // link to author's webpage
+  GdString date;                        // date of creation
+  char *story;                          // story for the cave - will be shown when cave is played.
+  char *remark;                         // some note
+
+  GdString charset;                     // these are not used by gdash
+  GdString fontset;
+
+  // and this one the highscores
+  GdHighScore highscore[GD_HIGHSCORE_NUM];
+
+  HashTable *tags;                      // stores read-but-not-understood strings from bdcff,
+                                        // so we can save them later.
+
+  GdElement **map;                      // pointer to data for map, non-null if has a map
+  List *objects;
+  List *replays;
+
+  boolean intermission;                 // is this cave an intermission?
+  boolean intermission_instantlife;     // one life extra, if the intermission is reached
+  boolean intermission_rewardlife;      // one life extra, if the intermission is finished
+  boolean selectable;                   // is this selectable as an initial cave for a game?
+  boolean diagonal_movements;           // are diagonal movements allowed?
+  GdElement snap_element;               // snapping (press fire+move) usually leaves space behind,
+                                        // but can be other
+  boolean short_explosions;             // in >= 1stb, diamond/creature explosions were of 5 stages
+
+  GdScheduling scheduling;              // scheduling type; see above
+  boolean pal_timing;                   // use faster seconds
+
+  boolean active_is_first_found;        // active player is the uppermost.
+  boolean lineshift;                    // true is line shifting emulation,
+                                        // false is perfect borders emulation
+  boolean border_scan_first_and_last;   // if true, scans the first and last line of the border.
+                                        // false for plck
+  boolean wraparound_objects;           // if this is true, object drawing (cave rendering)
+                                        // will wraparound as well.
+
+  GdElement initial_fill;
+  GdElement initial_border;
+  GdElement random_fill[4];             // Random fill elements.
+  int random_fill_probability[4];       // Random fill, probability of each element.
+
+  int level_rand[5];                    // Random seed.
+  int level_diamonds[5];                // Must collect diamonds, on level x
+  int level_speed[5];                   // Time between game cycles in ms
+  int level_ckdelay[5];                 // Timing in original game units
+  int level_time[5];                    // Available time, per level
+  int level_timevalue[5];               // points for each second remaining, when exiting level
+
+  int max_time;                         // the maximum time in seconds. if above, it overflows
+
+  int w, h;                             // Sizes of cave, width and height.
+  int x1,y1,x2,y2;                      // Visible part of the cave
+  GdColor colorb;                       // border color
+  GdColor color0, color1, color2, color3, color4, color5;    // c64-style colors;
+                                                             // color 4 and 5 are amoeba and slime.
+
+  int diamond_value;                    // Score for a diamond.
+  int extra_diamond_value;              // Score for a diamond, when gate is open.
+
+  boolean stone_sound;
+  boolean nut_sound;
+  boolean diamond_sound;
+  boolean nitro_sound;
+  boolean falling_wall_sound;
+  boolean expanding_wall_sound;
+  boolean bladder_spender_sound;
+  boolean bladder_convert_sound;
+
+  int level_magic_wall_time[5];         // magic wall 'on' state for each level (seconds)
+  boolean magic_wall_stops_amoeba;      // Turning on magic wall changes amoeba to diamonds.
+                                        // Original BD: yes, constkit: no
+  boolean magic_wall_breakscan;                // Currently this setting enabled will turn the amoeba to
+                                        // an enclosed state. To implement buggy BD1 behaviour.
+  boolean magic_timer_zero_is_infinite;        // magic wall timer 0 is interpreted as infinite
+  boolean magic_timer_wait_for_hatching;// magic wall timer does not start before player's birth
+  boolean magic_wall_sound;             // magic wall has sound
+
+  int level_amoeba_time[5];             // amoeba time for each level
+  int amoeba_growth_prob;               // Amoeba slow growth probability
+  int amoeba_fast_growth_prob;          // Amoeba fast growth probability
+  int level_amoeba_threshold[5];        // amoeba turns to stones; if count is bigger than this
+                                        // (number of cells)
+  GdElement amoeba_enclosed_effect;     // an enclosed amoeba converts to this element
+  GdElement amoeba_too_big_effect;      // an amoeba grown too big converts to this element
+
+  int level_amoeba_2_time[5];           // amoeba time for each level
+  int amoeba_2_growth_prob;             // Amoeba slow growth probability
+  int amoeba_2_fast_growth_prob;        // Amoeba fast growth probability
+  int level_amoeba_2_threshold[5];      // amoeba turns to stones; if count is bigger than this
+                                        // (number of cells)
+  GdElement amoeba_2_enclosed_effect;   // an enclosed amoeba converts to this element
+  GdElement amoeba_2_too_big_effect;    // an amoeba grown too big converts to this element
+  boolean amoeba_2_explodes_by_amoeba;  // amoeba 2 will explode if touched by amoeba1
+  GdElement amoeba_2_explosion_effect;  // amoeba 2 explosion ends in ...
+  GdElement amoeba_2_looks_like;        // an amoeba 2 looks like this element
+
+  boolean amoeba_timer_started_immediately; // FALSE: amoeba will start life at the first
+                                            //        possibility of growing.
+  boolean amoeba_timer_wait_for_hatching;   // amoeba timer does not start before player's birth
+  boolean amoeba_sound;                 // if the living amoeba has sound.
+
+  GdElement acid_eats_this;             // acid eats this element
+  int acid_spread_ratio;                // Probability of acid blowing up, each frame
+  boolean acid_spread_sound;            // acid has sound
+  GdElement acid_turns_to;              // whether acid converts to explosion on spreading or other
+
+  GdElement nut_turns_to_when_crushed;  // when nut is hit by stone, it converts to this element
+
+  int level_slime_permeability[5];      // true random slime
+  int level_slime_permeability_c64[5];  // Appearing in bd 2
+  int level_slime_seed_c64[5];          // predictable slime random seed
+  boolean slime_predictable;            // predictable random start for slime. yes for plck.
+  boolean slime_correct_random;         // correct random number generator for rendered caves
+  GdElement slime_eats_1, slime_converts_1; // slime eats element x and converts to element x;
+                                            // for example diamond -> falling diamond
+  GdElement slime_eats_2, slime_converts_2; // this is usually stone -> stone_f
+  GdElement slime_eats_3, slime_converts_3; // this is usually nut -> nut_f
+  boolean slime_sound;                  // slime has sound
+
+  boolean lava_sound;                   // elements sinking in lava have sound
+
+  int level_hatching_delay_frame[5];    // Scan frames before Player's birth.
+  int level_hatching_delay_time[5];     // Scan frames before Player's birth.
+
+  int level_bonus_time[5];              // bonus time for clock collected.
+  int level_penalty_time[5];            // Time penalty when voodoo destroyed.
+  boolean voodoo_collects_diamonds;     // Voodoo can collect diamonds
+  boolean voodoo_dies_by_stone;         // Voodoo can be killed by a falling stone
+  boolean voodoo_disappear_in_explosion;// Voodoo can be destroyed by and explosion
+  boolean voodoo_any_hurt_kills_player; // If any voodoo hurt in any way, player is killed.
+
+  boolean water_does_not_flow_down;     // if true, water will not grow downwards,
+                                        // only in other directions.
+  boolean water_sound;                  // water has sound
+
+  boolean bladder_sound;                // bladder moving and pushing has sound
+  GdElement bladder_converts_by;        // bladder converts to clock by touching this element
+
+  int biter_delay_frame;                // frame count biters do move
+  GdElement biter_eat;                  // biters eat this
+  boolean biter_sound;                  // biters have sound
+
+  boolean expanding_wall_changed;       // expanding wall direction is changed
+
+  int    replicator_delay_frame;        // replicator delay in frames (number of frames
+                                        // to wait between creating a new element)
+  boolean replicators_active;           // replicators are active.
+  boolean replicator_sound;             // when replicating an element, play sound or not.
+
+  boolean conveyor_belts_active;
+  boolean conveyor_belts_direction_changed;
+
+  // effects
+  GdElement explosion_effect;           // explosion converts to this element after its last stage.
+                                        // diego effect.
+  GdElement diamond_birth_effect;       // a diamond birth converts to this element after its last
+                                        // stage. diego effect.
+  GdElement bomb_explosion_effect;      // bombs explode to this element. diego effect (almost).
+  GdElement nitro_explosion_effect;     // nitros explode to this
+
+  GdElement firefly_explode_to;         // fireflies explode to this when hit by stone
+  GdElement alt_firefly_explode_to;     // alternative fireflies explode to this when hit by stone
+  GdElement butterfly_explode_to;       // butterflies explode to this when hit by stone
+  GdElement alt_butterfly_explode_to;   // alternative butterflies explode to this when hit by stone
+  GdElement stonefly_explode_to;        // stoneflies explode to this when hit by stone
+  GdElement dragonfly_explode_to;       // dragonflies explode to this when hit by stone
+
+  GdElement stone_falling_effect;       // falling stone converts to this element. diego effect.
+  GdElement diamond_falling_effect;     // falling diamond converts to this element. diego effect.
+  GdElement stone_bouncing_effect;      // bouncing stone converts to this element. diego effect.
+  GdElement diamond_bouncing_effect;    // bouncing diamond converts to this element. diego effect.
+
+  GdElement expanding_wall_looks_like;  // an expanding wall looks like this element. diego effect.
+  GdElement dirt_looks_like;            // dirt looks like this element. diego effect.
+
+  GdElement magic_stone_to;             // magic wall converts falling stone to
+  GdElement magic_diamond_to;           // magic wall converts falling diamond to
+  GdElement magic_mega_stone_to;        // magic wall converts a falling mega stone to
+  GdElement magic_nitro_pack_to;        // magic wall converts a falling nitro pack to
+  GdElement magic_nut_to;               // magic wall converts a falling nut to
+  GdElement magic_flying_stone_to;      // flying stones are converted to
+  GdElement magic_flying_diamond_to;    // flying diamonds are converted to
+
+  int pushing_stone_prob;               // probability of pushing stone
+  int pushing_stone_prob_sweet;         // probability of pushing, after eating sweet
+  boolean mega_stones_pushable_with_sweet; // mega stones may be pushed with sweet
+
+  boolean creatures_backwards;          // creatures changed direction
+  boolean creatures_direction_auto_change_on_start; // the change occurs also at the start signal
+  int creatures_direction_auto_change_time; // creatures automatically change direction every x
+                                            // seconds
+  boolean creature_direction_auto_change_sound; // automatically changing creature direction may
+                                                // have the sound of the creature dir switch
+
+  int skeletons_needed_for_pot;         // how many skeletons to be collected, to use a pot
+  int skeletons_worth_diamonds;         // for crazy dream 7 compatibility: collecting skeletons
+                                        // might open the cave door.
+
+  GdDirection gravity;
+  int gravity_change_time;
+  boolean gravity_change_sound;
+  boolean gravity_affects_all;          // if true, gravity also affects falling wall, bladder
+                                        // and waiting stones
+  boolean gravity_switch_active;        // true if gravity switch is activated, and can be used.
+
+  boolean hammered_walls_reappear;
+  int pneumatic_hammer_frame;
+  int hammered_wall_reappear_frame;
+  boolean pneumatic_hammer_sound;
+
+  boolean infinite_rockets;             // if true, the player which got a rocket launcher will be
+                                        // able to launch an infinite number of rockets
+
+  // internal variables, used during the game. private data :)
+
+  // returns range corrected x/y position (points to perfect or line shifting get function)
+  int (*getx) (const struct _gd_cave*, int x, int y);
+  int (*gety) (const struct _gd_cave*, int x, int y);
+
+  // returns pointer to element at x, y (points to perfect border or a line shifting get function)
+  GdElement* (*getp) (const struct _gd_cave*, int x, int y);
+
+  boolean hatched;                      // hatching has happened. (timers may run, ...)
+  boolean gate_open;                    // self-explaining
+  unsigned int render_seed;             // the seed value, which was used to render the cave,
+                                        // is saved here. will be used by record&playback
+  GdRand *random;                       // random number generator of rendered cave
+  int rendered;                         // if not zero, rendered at level x
+  int timing_factor;                    // number of "milliseconds" in each second :)
+                                        // 1000 for ntsc, 1200 for pal.
+  void ***objects_order;                // two-dimensional map of cave; each cell is a pointer
+                                        // to the drawing object, which created this element.
+                                        // NULL if map or random.
+  int **hammered_reappear;              // integer map of cave; if non-zero, a brick wall will
+                                        // appear there
+
+  int speed;                            // Time between game cycles in ms
+  int c64_timing;                       // a ckdelay value for the level this cave is rendered for
+  int ckdelay;                          // ckdelay value for the current iteration
+  int ckdelay_extra_for_animation;      // bd1 and similar engines had animation bits in cave data,
+                                        // to set which elements to animate (firefly, butterfly,
+                                        // amoeba).
+                                        // animating an element also caused some delay each frame;
+                                        //  according to my measurements, around 2.6 ms/element.
+
+  int frame;  // XXX
+
+  int hatching_delay_frame;
+  int hatching_delay_time;
+  int time_bonus;                       // bonus time for clock collected.
+  int time_penalty;                     // Time penalty when voodoo destroyed.
+  int time;                             // milliseconds remaining to finish cave
+  int timevalue;                        // points for remaining seconds - for current level
+  int diamonds_needed;                  // diamonds needed to open outbox
+  int diamonds_collected;               // diamonds collected
+  int skeletons_collected;              // number of skeletons collected
+  int gate_open_flash;                  // flashing of screen when gate opens
+  int score;                            // Score got this frame.
+  int amoeba_time;                      // Amoeba growing slow (low probability, default 3%) for
+                                        // milliseconds. After that, fast growth default (25%)
+  int amoeba_2_time;                    // Amoeba growing slow (low probability, default 3%) for
+                                        // milliseconds. After that, fast growth default (25%)
+  int amoeba_max_count;                 // selected amoeba 1 threshold for this level
+  int amoeba_2_max_count;               // selected amoeba 2 threshold for this level
+  GdAmoebaState amoeba_state;           // state of amoeba 1
+  GdAmoebaState amoeba_2_state;         // state of amoeba 2
+  boolean convert_amoeba_this_frame;    // To implement BD1 buggy amoeba+magic wall behaviour.
+  int magic_wall_time;                  // magic wall 'on' state for seconds
+  int slime_permeability;               // true random slime
+  int slime_permeability_c64;           // Appearing in bd 2
+  GdMagicWallState magic_wall_state;    // State of magic wall
+  GdPlayerState player_state;           // Player state. not yet living, living, exited...
+  int player_seen_ago;                  // player was seen this number of scans ago
+  boolean voodoo_touched;               // as its name says
+  boolean kill_player;                  // Voodoo died, or used pressed escape to restart level.
+  boolean sweet_eaten;                  // player ate sweet, he's strong. prob_sweet applies,
+                                        // and also able to push chasing stones
+  int player_x, player_y;               // Coordinates of player (for scrolling)
+  int px[16], py[16];                   // coordinates of player, for chasing stone
+  int key1, key2, key3;                 // The player is holding this number of keys of each color
+  boolean diamond_key_collected;        // Key collected, so trapped diamonds convert to diamonds
+  boolean inbox_flash_toggle;           // negated every scan. helps drawing inboxes, and making
+                                        // players be born at different times.
+  GdDirection last_direction;           // last direction player moved. used by draw routines
+  GdDirection last_horizontal_direction;
+  int biters_wait_frame;                // number of frames to wait until biters will move again
+  int replicators_wait_frame;           // number of frames to wait until replicators are
+                                        // activated again
+  int creatures_direction_will_change;  // creatures automatically change direction every x seconds
+  GdC64RandomGenerator c64_rand;        // used for predictable random generator during the game.
+
+  int gravity_will_change;              // gravity will change in this number of milliseconds
+  boolean gravity_disabled;             // when player is stirring the pot, there is no gravity.
+  GdDirection gravity_next_direction;   // next direction when the gravity changes.
+                                        // will be set by the player "getting" a gravity switch
+  boolean got_pneumatic_hammer;         // true if the player has a pneumatic hammer
+  int pneumatic_hammer_active_delay;    // number of frames to wait, till pneumatic hammer will
+                                        // destroy the wall
+  GdSound sound1, sound2, sound3;       // sound set for 3 channels after each iteration
+} GdCave;
+
+
+#define CAVE_OFFSET(property) (STRUCT_OFFSET(GdCave, property))
+
+// arrays for movements
+// also no1 and bd2 cave data import helpers; line direction coordinates
+extern const int gd_dx[], gd_dy[];
+
+extern GdElement gd_char_to_element[];
+
+void gd_create_char_to_element_table(void);
+GdElement gd_get_element_from_character(unsigned char character);
+GdElement gd_get_element_from_string(const char *string);
+
+// init cave engine
+void gd_cave_init(void);
+
+// for cave tags hash table
+int gd_str_case_equal(void *s1, void *s2);
+unsigned int gd_str_case_hash(void *v);
+
+// cave highscore functions
+int gd_highscore_compare(const void *a, const void *b);
+boolean gd_is_highscore(GdHighScore *scores, int score);
+int gd_add_highscore(GdHighScore *highscores, const char *name, int score);
+void gd_clear_highscore(GdHighScore *hs);
+boolean gd_has_highscore(GdHighScore *hs);
+
+// cave creator and destructor functions
+GdCave *gd_cave_new(void);
+GdCave *gd_cave_new_from_cave(const GdCave *orig);
+void gd_cave_copy(GdCave *dest, const GdCave *src);
+void gd_cave_free(GdCave *cave);
+
+// cave manipulation
+void gd_cave_set_gdash_defaults(GdCave *cave);
+void gd_cave_set_defaults_from_array(GdCave* cave, GdPropertyDefault *defaults);
+void gd_cave_correct_visible_size(GdCave *cave);
+void gd_cave_set_random_colors(GdCave *cave, GdColorType type);
+void gd_cave_auto_shrink(GdCave *cave);
+
+void gd_cave_setup_for_game(GdCave *cave);
+void gd_cave_count_diamonds(GdCave *cave);
+
+// c64 random generator support for cave fill
+unsigned int gd_c64_random(GdC64RandomGenerator *rand);
+unsigned int gd_cave_c64_random(GdCave *);
+void gd_c64_random_set_seed(GdC64RandomGenerator *rand, int seed1, int seed2);
+void gd_cave_c64_random_set_seed(GdCave *cave, int seed1, int seed2);
+void gd_cave_set_random_c64_colors(GdCave *cave);
+
+// support
+void *gd_cave_map_new_for_cave(const GdCave *cave, const int cell_size);
+void *gd_cave_map_dup_size(const GdCave * cave, const void *map, const int cell_size);
+#define gd_cave_map_new(CAVE, TYPE) ((TYPE **)gd_cave_map_new_for_cave((CAVE), sizeof(TYPE)))
+#define gd_cave_map_dup(CAVE, MAP) ((void *)gd_cave_map_dup_size((CAVE), (void **)(CAVE)->MAP, sizeof((CAVE)->MAP[0][0])))
+void gd_cave_map_free(void *map);
+
+void gd_cave_store_rc(GdCave * cave, int x, int y, const GdElement element, const void* order);
+GdElement gd_cave_get_rc (const GdCave *cave, int x, int y);
+
+// direction
+const char *gd_direction_get_visible_name(GdDirection dir);
+const char *gd_direction_get_filename(GdDirection dir);
+GdDirection gd_direction_from_string(const char *str);
+
+// scheduling
+const char *gd_scheduling_get_visible_name(GdScheduling sched);
+const char *gd_scheduling_get_filename(GdScheduling sched);
+GdScheduling gd_scheduling_from_string(const char *str);
+
+// game playing helpers
+#define GD_REDRAW (1 << 10)
+
+void gd_drawcave_game(const GdCave *cave,
+                     int **element_buffer, int **last_element_buffer, int **gfx_buffer,
+                     boolean bonus_life_flash, int animcycle, boolean hate_invisible_outbox);
+
+// function to copy a GdString
+static inline char *gd_strcpy(GdString dest, const GdString src)
+{
+    return strncpy(dest, src, sizeof(GdString));
+}
+
+int gd_cave_time_show(const GdCave *cave, int internal_time);
+
+GdReplay *gd_replay_new(void);
+GdReplay *gd_replay_new_from_replay(GdReplay *orig);
+void gd_replay_free(GdReplay *replay);
+void gd_replay_store_movement(GdReplay *replay, GdDirection player_move, boolean player_fire, boolean suicide);
+
+unsigned int gd_cave_adler_checksum(GdCave *cave);
+void gd_cave_adler_checksum_more(GdCave *cave, unsigned int *a, unsigned int *b);
+
+boolean gd_cave_has_levels(GdCave *cave);
+boolean gd_caveset_has_levels(void);
+
+#endif // BD_CAVE_H
diff --git a/src/game_bd/bd_cavedb.c b/src/game_bd/bd_cavedb.c
new file mode 100644 (file)
index 0000000..45da297
--- /dev/null
@@ -0,0 +1,1143 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+// some cells are created inside the game (by merging two cells from the png etc);
+// those are used only in the editor.
+// this enum is used to give each and every one a different index automatically.
+enum _generated_cells_indexes
+{
+  // the first one gets the first available index.
+  // the following ones will be generated by the compiler automatically.
+  i_stonefly_1 = GD_NUM_OF_CELLS_X * GD_NUM_OF_CELLS_Y,
+  i_stonefly_2,
+  i_stonefly_3,
+  i_stonefly_4,
+  i_alt_guard_1,
+  i_alt_guard_2,
+  i_alt_guard_3,
+  i_alt_guard_4,
+  i_steel_eatable,
+  i_brick_eatable,
+  i_dirt_glued,
+  i_diamond_glued,
+  i_stone_glued,
+  i_falling_wall,
+  i_falling_wall_falling,
+  i_expanding_wall,
+  i_h_expanding_wall,
+  i_v_expanding_wall,
+  i_expanding_steel_wall,
+  i_h_expanding_steel_wall,
+  i_v_expanding_steel_wall,
+  i_mega_stone_falling,
+  i_time_penalty,
+  i_biter_1,
+  i_biter_2,
+  i_biter_3,
+  i_biter_4,
+  i_cow_1,
+  i_cow_2,
+  i_cow_3,
+  i_cow_4,
+  i_guard_1,
+  i_guard_2,
+  i_guard_3,
+  i_guard_4,
+  i_butter_1,
+  i_butter_2,
+  i_butter_3,
+  i_butter_4,
+  i_dragonfly_1,
+  i_dragonfly_2,
+  i_dragonfly_3,
+  i_dragonfly_4,
+  i_cow_enclosed,
+  i_pre_outbox_nonblink,
+  i_invis_outbox,
+  i_brick_non_sloped,
+  i_outbox,
+  i_stone_f,
+  i_flying_stone_f,
+  i_diamond_f,
+  i_flying_diamond_f,
+  i_pre_invis_outbox,
+  i_unknown,
+  i_waiting_stone,
+  i_pre_outbox_frame_1,    // this will have 8 frames.
+  i_pre_outbox_frame_2,
+  i_pre_outbox_frame_3,
+  i_pre_outbox_frame_4,
+  i_pre_outbox_frame_5,
+  i_pre_outbox_frame_6,
+  i_pre_outbox_frame_7,
+  i_pre_outbox_frame_8,
+  i_nitro_pack_f,
+  i_alt_butter_1,
+  i_alt_butter_2,
+  i_alt_butter_3,
+  i_alt_butter_4,
+  i_conveyor_left,
+  i_conveyor_right,
+  i_nitro_explode,
+  i_walled_diamond,
+  i_walled_key_1,
+  i_walled_key_2,
+  i_walled_key_3,
+  i_player,
+  i_player_glued,
+  i_nut_f,
+
+  i_max_cell_num
+};
+
+/*
+  elements description array. do not miss an index!
+  the game will check if one is missing and stop the game.
+  the identifier in the saved file might also not match, reading an "outbox" from
+  the file should store an O_PRE_OUTBOX.
+
+  images are: image in editor, image in editor - animated, game image
+  indexes which are in the png have to be given as numeric constants.
+  for generated cells (ie. guard + an arrow), use the above enum
+*/
+GdElements gd_elements[] =
+{
+  { O_SPACE, N_("Space"), P_AMOEBA_CONSUMES, "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_SLOPED_DOWN_LEFT, N_("Sloped dirt (down & left)"), P_DIRT | P_SLOPED_DOWN | P_SLOPED_LEFT | P_AMOEBA_CONSUMES | P_DIGGABLE, "DIRTSLOPEDDOWNLEFT", 0, 282, 282, 282 },
+  { O_DIRT_SLOPED_DOWN_RIGHT, N_("Sloped dirt (down & right)"), P_DIRT | P_SLOPED_DOWN | P_SLOPED_RIGHT | P_AMOEBA_CONSUMES | P_DIGGABLE, "DIRTSLOPEDDOWNRIGHT", 0, 283, 283, 283 },
+  { O_DIRT_BALL, N_("Dirt ball"), P_DIRT | P_SLOPED | P_AMOEBA_CONSUMES | P_MOVED_BY_CONVEYOR_TOP | P_DIGGABLE | P_CAN_FALL, "DIRTBALL", 0, 289, 289, 289, 120 },    // has ckdelay
+  { O_DIRT_BALL_F, N_("Dirt ball (falling)"), P_FALLING | P_DIGGABLE, "DIRTBALLf", 0, 289, 289, 289, 120 },    // has ckdelay
+  { O_DIRT_LOOSE, N_("Loose dirt"), P_DIRT | P_AMOEBA_CONSUMES | P_MOVED_BY_CONVEYOR_TOP | P_DIGGABLE | P_CAN_FALL, "DIRTLOOSE", 0, 352, 352, 352, 60 },    // has ckdelay
+  { O_DIRT_LOOSE_F, N_("Loose dirt (falling)"), P_FALLING, "DIRTLOOSEf", 0, 352, 352, 352, 60 },    // has ckdelay
+  { O_DIRT2, N_("Dirt 2"), P_DIRT | P_AMOEBA_CONSUMES | P_DIGGABLE, "DIRT2", 0, 3, 3, 3 },
+  { O_BRICK, N_("Brick wall"), P_SLOPED|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALL", 'w', 5, 5, 5 },
+  { O_BRICK_SLOPED_UP_RIGHT, N_("Sloped brick wall (up & right)"), P_SLOPED_UP|P_SLOPED_RIGHT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDUPRIGHT", 0, 276, 276, 276 },
+  { O_BRICK_SLOPED_UP_LEFT, N_("Sloped brick wall (up & left)"), P_SLOPED_UP|P_SLOPED_LEFT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDUPLEFT", 0, 277, 277, 277 },
+  { O_BRICK_SLOPED_DOWN_LEFT, N_("Sloped brick wall (down & left)"), P_SLOPED_DOWN|P_SLOPED_LEFT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDDOWNLEFT", 0, 278, 278, 278 },
+  { O_BRICK_SLOPED_DOWN_RIGHT, N_("Sloped brick wall (down & right)"), P_SLOPED_DOWN|P_SLOPED_RIGHT|P_BLADDER_SLOPED|P_CAN_BE_HAMMERED, "WALLSLOPEDDOWNRIGHT", 0, 279, 279, 279 },
+  { O_BRICK_NON_SLOPED, N_("Non-sloped brick wall"), P_CAN_BE_HAMMERED, "WALLNONSLOPED", 0, i_brick_non_sloped, i_brick_non_sloped, 5 },
+  { O_MAGIC_WALL, N_("Magic wall"), P_CAN_BE_HAMMERED, "MAGICWALL", 'M', 184, -184, -184 },
+  { O_PRE_OUTBOX, N_("Outbox"), 0, "OUTBOX", 'X', i_pre_outbox_nonblink, -i_pre_outbox_frame_1, 22 },
+  { O_OUTBOX, N_("Outbox (open)"), 0, "OUTBOXopen", 0, i_outbox, i_outbox, 22 },
+  { O_PRE_INVIS_OUTBOX, N_("Invisible outbox"), 0, "HIDDENOUTBOX", 'H', i_pre_invis_outbox, i_pre_invis_outbox, 22 },
+  { O_INVIS_OUTBOX, N_("Invisible outbox (open)"), 0, "HIDDENOUTBOXopen", 0, i_invis_outbox, i_invis_outbox, 22 },
+  { O_STEEL, N_("Steel wall"), P_NON_EXPLODABLE, "STEELWALL", 'W', 4, 4, 4 },
+  { O_STEEL_SLOPED_UP_RIGHT, N_("Sloped steel wall (up & right)"), P_SLOPED_UP|P_SLOPED_RIGHT|P_NON_EXPLODABLE, "STEELWALLSLOPEDUPRIGHT", 0, 284, 284, 284 },
+  { O_STEEL_SLOPED_UP_LEFT, N_("Sloped steel wall (up & left)"), P_SLOPED_UP|P_SLOPED_LEFT|P_NON_EXPLODABLE, "STEELWALLSLOPEDUPLEFT", 0, 285, 285, 285 },
+  { O_STEEL_SLOPED_DOWN_LEFT, N_("Sloped steel wall (down & left)"), P_SLOPED_DOWN|P_SLOPED_LEFT|P_NON_EXPLODABLE, "STEELWALLSLOPEDDOWNLEFT", 0, 286, 286, 286 },
+  { O_STEEL_SLOPED_DOWN_RIGHT, N_("Sloped steel wall (down & right)"), P_SLOPED_DOWN|P_SLOPED_RIGHT|P_NON_EXPLODABLE, "STEELWALLSLOPEDDOWNRIGHT", 0, 287, 287, 287 },
+  { O_STEEL_EXPLODABLE, N_("Explodable steel wall"), P_CAN_BE_HAMMERED, "STEELWALLDESTRUCTABLE", 'E', 72, 72, 4 },
+  { O_STEEL_EATABLE, N_("Eatable steel wall"), P_DIGGABLE, "STEELWALLEATABLE", 0, i_steel_eatable, i_steel_eatable, 4 },
+  { O_BRICK_EATABLE, N_("Eatable brick wall"), P_DIGGABLE, "WALLEATABLE", 0, i_brick_eatable, i_brick_eatable, 5 },
+  { O_STONE, N_("Stone"), P_SLOPED | P_MOVED_BY_CONVEYOR_TOP | P_PUSHABLE | P_CAN_FALL, "BOULDER", 'r', 1, 1, 1, 156 },    // has ckdelay
+  { O_STONE_F, N_("Stone, falling"), P_FALLING, "BOULDERf", 'R', i_stone_f, i_stone_f, 1, 156 },    // has ckdelay
+  { O_FLYING_STONE, N_("Flying stone"), P_SLOPED | P_MOVED_BY_CONVEYOR_BOTTOM | P_PUSHABLE | P_CAN_FALL, "FLYINGBOULDER", 0, 357, 357, 357, 156 },    // has ckdelay
+  { O_FLYING_STONE_F, N_("Flying stone, flying"), P_FALLING, "FLYINGBOULDERf", 0, i_flying_stone_f, i_flying_stone_f, 357, 156 },    // has ckdelay
+  { O_MEGA_STONE, N_("Mega stone"), P_SLOPED | P_MOVED_BY_CONVEYOR_TOP | P_PUSHABLE | P_CAN_FALL, "MEGABOULDER", 0, 272, 272, 272, 156 },    // has ckdelay
+  { O_MEGA_STONE_F, N_("Mega stone, falling"), P_FALLING, "MEGABOULDERf", 0, i_mega_stone_falling, i_mega_stone_falling, 272, 156 },    // has ckdelay
+  { O_DIAMOND, N_("Diamond"), P_SLOPED | P_MOVED_BY_CONVEYOR_TOP | P_COLLECTIBLE | P_CAN_FALL, "DIAMOND", 'd', 248, -248, -248, 156 },    // has ckdelay
+  { O_DIAMOND_F, N_("Diamond, falling"), P_FALLING, "DIAMONDf", 'D', i_diamond_f, i_diamond_f, -248, 156 },    // has ckdelay
+  { O_FLYING_DIAMOND, N_("Flying diamond"), P_SLOPED | P_MOVED_BY_CONVEYOR_BOTTOM | P_COLLECTIBLE | P_CAN_FALL, "FLYINGDIAMOND", 0, 344, -344, -344, 156 },    // has ckdelay
+  { O_FLYING_DIAMOND_F, N_("Flying diamond, flying"), P_FALLING, "FLYINGDIAMONDf", 0, i_flying_diamond_f, i_flying_diamond_f, -344, 156 },    // has ckdelay
+  { O_NUT, N_("Nut"), P_SLOPED | P_MOVED_BY_CONVEYOR_TOP | P_PUSHABLE | P_CAN_FALL, "NUT", 0, 358, 358, 358, 156 },    // has ckdelay
+  { 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_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_REPLICATOR_SWITCH, N_("Replicator switch"), 0, "REPLICATORSWITCH", 0, 290, 290, 290 },
+  { O_CONVEYOR_SWITCH, N_("Conveyor belt power switch"), 0, "CONVEYORSWITCH", 0, 356, 356, 356 },
+  { O_CONVEYOR_DIR_SWITCH, N_("Conveyor belt direction switch"), 0, "CONVEYORDIRECTIONSWITCH", 0, 353, 353, 353 },
+  { O_ACID, N_("Acid"), 0, "ACID", 0, 20, 20, 20, 128 },    // has ckdelay
+  { O_FALLING_WALL, N_("Falling wall"), P_CAN_BE_HAMMERED | P_CAN_FALL, "FALLINGWALL", 0, i_falling_wall, i_falling_wall, 5, 80 },    // has ckdelay
+  { O_FALLING_WALL_F, N_("Falling wall, falling"), P_CAN_BE_HAMMERED | P_FALLING, "FALLINGWALLf", 0, i_falling_wall_falling, i_falling_wall_falling, 5, 80 },    // has ckdelay
+  { O_BOX, N_("Box"), P_PUSHABLE, "SOKOBANBOX", 0, 21, 21, 21 },
+  { O_TIME_PENALTY, N_("Time penalty"), P_NON_EXPLODABLE, "TIMEPENALTY", 0, i_time_penalty, i_time_penalty, 9 },
+  { O_GRAVESTONE, N_("Gravestone"), P_NON_EXPLODABLE, "GRAVESTONE", 'G', 9, 9, 9 },
+  { O_STONE_GLUED, N_("Glued stone"), P_SLOPED, "GLUEDBOULDER", 0, i_stone_glued, i_stone_glued, 1 },
+  { O_DIAMOND_GLUED, N_("Glued diamond"), P_SLOPED, "GLUEDDIAMOND", 0, i_diamond_glued, i_diamond_glued, -248 },
+  { O_DIAMOND_KEY, N_("Diamond key"), P_COLLECTIBLE, "DIAMONDRELEASEKEY", 0, 11, 11, 11 },
+  { O_TRAPPED_DIAMOND, N_("Trapped diamond"), P_NON_EXPLODABLE, "TRAPPEDDIAMOND", 0, 10, 10, 10 },
+  { O_CLOCK, N_("Clock"), P_COLLECTIBLE, "CLOCK", 0, 16, 16, 16 },
+  { O_DIRT_GLUED, N_("Glued dirt"), 0, "GLUEDDIRT", 0, i_dirt_glued, i_dirt_glued, 2 },
+  { O_KEY_1, N_("Key 1"), P_COLLECTIBLE, "KEY1", 0, 67, 67, 67 },
+  { O_KEY_2, N_("Key 2"), P_COLLECTIBLE, "KEY2", 0, 68, 68, 68 },
+  { O_KEY_3, N_("Key 3"), P_COLLECTIBLE, "KEY3", 0, 69, 69, 69 },
+  { O_DOOR_1, N_("Door 1"), 0, "DOOR1", 0, 64, 64, 64 },
+  { O_DOOR_2, N_("Door 2"), 0, "DOOR2", 0, 65, 65, 65 },
+  { O_DOOR_3, N_("Door 3"), 0, "DOOR3", 0, 66, 66, 66 },
+
+  { 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_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_WATER_2, N_("Water (2)"), 0, "WATER2", 0, 96, -96, -96 },
+  { O_WATER_3, N_("Water (3)"), 0, "WATER3", 0, 96, -96, -96 },
+  { O_WATER_4, N_("Water (4)"), 0, "WATER4", 0, 96, -96, -96 },
+  { O_WATER_5, N_("Water (5)"), 0, "WATER5", 0, 96, -96, -96 },
+  { O_WATER_6, N_("Water (6)"), 0, "WATER6", 0, 96, -96, -96 },
+  { O_WATER_7, N_("Water (7)"), 0, "WATER7", 0, 96, -96, -96 },
+  { O_WATER_8, N_("Water (8)"), 0, "WATER8", 0, 96, -96, -96 },
+  { O_WATER_9, N_("Water (9)"), 0, "WATER9", 0, 96, -96, -96 },
+  { O_WATER_10, N_("Water (10)"), 0, "WATER10", 0, 96, -96, -96 },
+  { O_WATER_11, N_("Water (11)"), 0, "WATER11", 0, 96, -96, -96 },
+  { O_WATER_12, N_("Water (12)"), 0, "WATER12", 0, 96, -96, -96 },
+  { O_WATER_13, N_("Water (13)"), 0, "WATER13", 0, 96, -96, -96 },
+  { O_WATER_14, N_("Water (14)"), 0, "WATER14", 0, 96, -96, -96 },
+  { O_WATER_15, N_("Water (15)"), 0, "WATER15", 0, 96, -96, -96 },
+  { O_WATER_16, N_("Water (16)"), 0, "WATER16", 0, 96, -96, -96 },
+  { O_COW_1, N_("Cow (left)"), P_CCW | P_CAN_MOVE, "COWl", 0, i_cow_1, -88, -88, 384 },    // has ckdelay
+  { O_COW_2, N_("Cow (up)"), P_CCW | P_CAN_MOVE, "COWu", 0, i_cow_2, -88, -88, 384 },      // has ckdelay
+  { O_COW_3, N_("Cow (right)"), P_CCW | P_CAN_MOVE, "COWr", 0, i_cow_3, -88, -88, 384 },   // has ckdelay
+  { O_COW_4, N_("Cow (down)"), P_CCW | P_CAN_MOVE, "COWd", 0, i_cow_4, -88, -88, 384 },    // has ckdelay
+  { O_COW_ENCLOSED_1, N_("Cow (enclosed, 1)"), 0, "COW_ENCLOSED1", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_2, N_("Cow (enclosed, 2)"), 0, "COW_ENCLOSED2", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_3, N_("Cow (enclosed, 3)"), 0, "COW_ENCLOSED3", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_4, N_("Cow (enclosed, 4)"), 0, "COW_ENCLOSED4", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_5, N_("Cow (enclosed, 5)"), 0, "COW_ENCLOSED5", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_6, N_("Cow (enclosed, 6)"), 0, "COW_ENCLOSED6", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_COW_ENCLOSED_7, N_("Cow (enclosed, 7)"), 0, "COW_ENCLOSED7", 0, i_cow_enclosed, -88, -88, 120 },    // has ckdelay
+  { O_WALLED_DIAMOND, N_("Walled diamond"), P_CAN_BE_HAMMERED, "WALLED_DIAMOND", 0, i_walled_diamond, i_walled_diamond, 5 },
+  { O_WALLED_KEY_1, N_("Walled key 1"), P_CAN_BE_HAMMERED, "WALLED_KEY1", 0, i_walled_key_1, i_walled_key_1, 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_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_LAVA, N_("Lava"), P_NON_EXPLODABLE, "LAVA", 0, 312, -312, -312 },
+  { 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_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_GHOST, N_("Ghost"), P_CAN_MOVE, "GHOST", 'g', 160, -160, -160, 50 },    // has ckdelay
+  { O_FIREFLY_1, N_("Guard, left"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "FIREFLYl", 'Q', i_guard_1, -136, -136, 384 },    // has ckdelay
+  { O_FIREFLY_2, N_("Guard, up"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "FIREFLYu", 'o', i_guard_2, -136, -136, 384 },      // has ckdelay
+  { O_FIREFLY_3, N_("Guard, right"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "FIREFLYr", 'O', i_guard_3, -136, -136, 384 },   // has ckdelay
+  { O_FIREFLY_4, N_("Guard, down"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "FIREFLYd", 'q', i_guard_4, -136, -136, 384 },    // has ckdelay
+  { O_ALT_FIREFLY_1, N_("Alternative guard, left"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "A_FIREFLYl", 0, i_alt_guard_1, -104, -104, 384 },    // has ckdelay
+  { O_ALT_FIREFLY_2, N_("Alternative guard, up"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "A_FIREFLYu", 0, i_alt_guard_2, -104, -104, 384 },      // has ckdelay
+  { O_ALT_FIREFLY_3, N_("Alternative guard, right"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "A_FIREFLYr", 0, i_alt_guard_3, -104, -104, 384 },   // has ckdelay
+  { O_ALT_FIREFLY_4, N_("Alternative guard, down"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "A_FIREFLYd", 0, i_alt_guard_4, -104, -104, 384 },    // has ckdelay
+  { O_BUTTER_1, N_("Butterfly, left"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "BUTTERFLYl", 'C', i_butter_1, -144, -144, 384 },    // has ckdelay
+  { O_BUTTER_2, N_("Butterfly, up"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "BUTTERFLYu", 'b', i_butter_2, -144, -144, 384 },      // has ckdelay
+  { O_BUTTER_3, N_("Butterfly, right"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "BUTTERFLYr", 'B', i_butter_3, -144, -144, 384 },   // has ckdelay
+  { O_BUTTER_4, N_("Butterfly, down"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "BUTTERFLYd", 'c', i_butter_4, -144, -144, 384 },    // has ckdelay
+  { O_ALT_BUTTER_1, N_("Alternative butterfly, left"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "A_BUTTERFLYl", 0, i_alt_butter_1, -112, -112, 384 },    // has ckdelay
+  { O_ALT_BUTTER_2, N_("Alternative butterfly, up"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "A_BUTTERFLYu", 0, i_alt_butter_2, -112, -112, 384 },      // has ckdelay
+  { O_ALT_BUTTER_3, N_("Alternative butterfly, right"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "A_BUTTERFLYr", 0, i_alt_butter_3, -112, -112, 384 },   // has ckdelay
+  { O_ALT_BUTTER_4, N_("Alternative butterfly, down"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "A_BUTTERFLYd", 0, i_alt_butter_4, -112, -112, 384 },    // has ckdelay
+  { O_STONEFLY_1, N_("Stonefly, left"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "STONEFLYl", 0, i_stonefly_1, -152, -152, 384 },    // has ckdelay
+  { O_STONEFLY_2, N_("Stonefly, up"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "STONEFLYu", 0, i_stonefly_2, -152, -152, 384 },      // has ckdelay
+  { O_STONEFLY_3, N_("Stonefly, right"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "STONEFLYr", 0, i_stonefly_3, -152, -152, 384 },   // has ckdelay
+  { O_STONEFLY_4, N_("Stonefly, down"), P_EXPLODES_BY_HIT | P_CAN_MOVE, "STONEFLYd", 0, i_stonefly_4, -152, -152, 384 },    // has ckdelay
+  { O_BITER_1, N_("Biter, up"), P_CAN_MOVE, "BITERu", 0, i_biter_1, -168, -168, 518 },    // has ckdelay
+  { O_BITER_2, N_("Biter, right"), P_CAN_MOVE, "BITERr", 0, i_biter_2, -168, -168, 518 },    // has ckdelay
+  { O_BITER_3, N_("Biter, down"), P_CAN_MOVE, "BITERd", 0, i_biter_3, -168, -168, 518 },    // has ckdelay
+  { O_BITER_4, N_("Biter, left"), P_CAN_MOVE, "BITERl", 0, i_biter_4, -168, -168, 518 },    // has ckdelay
+  { O_DRAGONFLY_1, N_("Dragonfly, left"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "DRAGONFLYl", 0, i_dragonfly_1, -336, -336, 256  },    // has ckdelay
+  { O_DRAGONFLY_2, N_("Dragonfly, up"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "DRAGONFLYu", 0, i_dragonfly_2, -336, -336, 256  },      // has ckdelay
+  { O_DRAGONFLY_3, N_("Dragonfly, right"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "DRAGONFLYr", 0, i_dragonfly_3, -336, -336, 256  },   // has ckdelay
+  { O_DRAGONFLY_4, N_("Dragonfly, down"), P_EXPLODES_BY_HIT | P_CCW | P_CAN_MOVE, "DRAGONFLYd", 0, i_dragonfly_4, -336, -336, 256  },    // has ckdelay
+
+  { 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_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_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_6, N_("Ticking bomb (6)"), 0, "IGNITEDBOMB6", 0, 54, 54, 54 },
+  { O_BOMB_TICK_7, N_("Ticking bomb (7)"), 0, "IGNITEDBOMB7", 0, 55, 55, 55 },
+
+  { O_NITRO_PACK, N_("Nitro pack"), P_SLOPED | P_EXPLODES_BY_HIT | P_MOVED_BY_CONVEYOR_TOP | P_PUSHABLE | P_CAN_FALL, "NITRO", 0, 288, 288, 288 },
+  { O_NITRO_PACK_F, N_("Nitro pack, falling"), P_EXPLODES_BY_HIT | P_FALLING, "NITROf", 0, i_nitro_pack_f, i_nitro_pack_f, 288 },
+  { O_NITRO_PACK_EXPLODE, N_("Nitro pack, triggered"), P_EXPLODES_BY_HIT, "NITROtriggered", 0, i_nitro_explode, i_nitro_explode, 288 },
+
+  { O_PRE_CLOCK_1, N_("Clock birth (1)"), P_GROWING | P_EXPLOSION_FIRST_STAGE, "CLOCKBIRTH1", 0, 28, 28, 28, 280 },    // has ckdelay
+  { O_PRE_CLOCK_2, N_("Clock birth (2)"), P_GROWING, "CLOCKBIRTH2", 0, 29, 29, 29, 280 },    // has ckdelay
+  { O_PRE_CLOCK_3, N_("Clock birth (3)"), P_GROWING, "CLOCKBIRTH3", 0, 30, 30, 30, 280 },    // has ckdelay
+  { O_PRE_CLOCK_4, N_("Clock birth (4)"), P_GROWING, "CLOCKBIRTH4", 0, 31, 31, 31, 280 },    // has ckdelay
+  { O_PRE_DIA_1, N_("Diamond birth (1)"), P_GROWING | P_EXPLOSION_FIRST_STAGE, "DIAMONDBIRTH1", 0, 56, 56, 56, 280 },    // has ckdelay
+  { O_PRE_DIA_2, N_("Diamond birth (2)"), P_GROWING, "DIAMONDBIRTH2", 0, 57, 57, 57, 280 },    // has ckdelay
+  { O_PRE_DIA_3, N_("Diamond birth (3)"), P_GROWING, "DIAMONDBIRTH3", 0, 58, 58, 58, 280 },    // has ckdelay
+  { O_PRE_DIA_4, N_("Diamond birth (4)"), P_GROWING, "DIAMONDBIRTH4", 0, 59, 59, 59, 280 },    // has ckdelay
+  { O_PRE_DIA_5, N_("Diamond birth (5)"), P_GROWING, "DIAMONDBIRTH5", 0, 60, 60, 60, 280 },    // has ckdelay
+  { O_EXPLODE_1, N_("Explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "EXPLOSION1", 0, 43, 43, 43, 280 },    // has ckdelay
+  { O_EXPLODE_2, N_("Explosion (2)"), P_EXPLOSION, "EXPLOSION2", 0, 44, 44, 44, 280 },    // has ckdelay
+  { O_EXPLODE_3, N_("Explosion (3)"), P_EXPLOSION, "EXPLOSION3", 0, 45, 45, 45, 280 },    // has ckdelay
+  { O_EXPLODE_4, N_("Explosion (4)"), P_EXPLOSION, "EXPLOSION4", 0, 46, 46, 46, 280 },    // has ckdelay
+  { O_EXPLODE_5, N_("Explosion (5)"), P_EXPLOSION, "EXPLOSION5", 0, 47, 47, 47, 280 },    // has ckdelay
+  { O_PRE_STONE_1, N_("Stone birth (1)"), P_GROWING | P_EXPLOSION_FIRST_STAGE, "BOULDERBIRTH1", 0, 36, 36, 36, 280 },    // has ckdelay
+  { O_PRE_STONE_2, N_("Stone birth (2)"), P_GROWING, "BOULDERBIRTH2", 0, 37, 37, 37, 280 },    // has ckdelay
+  { O_PRE_STONE_3, N_("Stone birth (3)"), P_GROWING, "BOULDERBIRTH3", 0, 38, 38, 38, 280 },    // has ckdelay
+  { O_PRE_STONE_4, N_("Stone birth (4)"), P_GROWING, "BOULDERBIRTH4", 0, 39, 39, 39, 280 },    // has ckdelay
+  { O_PRE_STEEL_1, N_("Steel birth (1)"), P_GROWING | P_EXPLOSION_FIRST_STAGE, "STEELWALLBIRTH1", 0, 24, 24, 24, 280 },    // has ckdelay
+  { O_PRE_STEEL_2, N_("Steel birth (2)"), P_GROWING, "STEELWALLBIRTH2", 0, 25, 25, 25, 280 },    // has ckdelay
+  { O_PRE_STEEL_3, N_("Steel birth (3)"), P_GROWING, "STEELWALLBIRTH3", 0, 26, 26, 26, 280 },    // has ckdelay
+  { O_PRE_STEEL_4, N_("Steel birth (4)"), P_GROWING, "STEELWALLBIRTH4", 0, 27, 27, 27, 280 },    // has ckdelay
+  { O_GHOST_EXPL_1, N_("Ghost explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "GHOSTEXPLOSION1", 0, 80, 80, 80, 280 },    // has ckdelay
+  { O_GHOST_EXPL_2, N_("Ghost explosion (2)"), P_EXPLOSION, "GHOSTEXPLOSION2", 0, 81, 81, 81, 280 },    // has ckdelay
+  { O_GHOST_EXPL_3, N_("Ghost explosion (3)"), P_EXPLOSION, "GHOSTEXPLOSION3", 0, 82, 82, 82, 280 },    // has ckdelay
+  { O_GHOST_EXPL_4, N_("Ghost explosion (4)"), P_EXPLOSION, "GHOSTEXPLOSION4", 0, 83, 83, 83, 280 },    // has ckdelay
+  { O_BOMB_EXPL_1, N_("Bomb explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "BOMBEXPLOSION1", 0, 84, 84, 84, 280 },    // has ckdelay
+  { O_BOMB_EXPL_2, N_("Bomb explosion (2)"), P_EXPLOSION, "BOMBEXPLOSION2", 0, 85, 85, 85, 280 },    // has ckdelay
+  { O_BOMB_EXPL_3, N_("Bomb explosion (3)"), P_EXPLOSION, "BOMBEXPLOSION3", 0, 86, 86, 86, 280 },    // has ckdelay
+  { O_BOMB_EXPL_4, N_("Bomb explosion (4)"), P_EXPLOSION, "BOMBEXPLOSION4", 0, 87, 87, 87, 280 },    // has ckdelay
+  { O_NITRO_EXPL_1, N_("Nitro pack explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "NITROEXPLOSION1", 0, 44, 44, 44, 280 },    // has ckdelay
+  { O_NITRO_EXPL_2, N_("Nitro pack explosion (2)"), P_EXPLOSION, "NITROEXPLOSION2", 0, 45, 45, 45, 280 },    // has ckdelay
+  { O_NITRO_EXPL_3, N_("Nitro pack explosion (3)"), P_EXPLOSION, "NITROEXPLOSION3", 0, 46, 46, 46, 280 },    // has ckdelay
+  { O_NITRO_EXPL_4, N_("Nitro pack explosion (4)"), P_EXPLOSION, "NITROEXPLOSION4", 0, 47, 47, 47, 280 },    // has ckdelay
+  { O_AMOEBA_2_EXPL_1, N_("Amoeba 2 explosion (1)"), P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "AMOEBA2EXPLOSION1", 0, 292, 292, 292, 280 },    // has ckdelay
+  { O_AMOEBA_2_EXPL_2, N_("Amoeba 2 explosion (2)"), P_EXPLOSION, "AMOEBA2EXPLOSION2", 0, 293, 293, 293, 280 },    // has ckdelay
+  { O_AMOEBA_2_EXPL_3, N_("Amoeba 2 explosion (3)"), P_EXPLOSION, "AMOEBA2EXPLOSION3", 0, 294, 294, 294, 280 },    // has ckdelay
+  { O_AMOEBA_2_EXPL_4, N_("Amoeba 2 explosion (4)"), P_EXPLOSION, "AMOEBA2EXPLOSION4", 0, 295, 295, 295, 280 },    // has ckdelay
+  { O_NUT_EXPL_1, N_("Nut explosion (1)"), P_SLOPED | P_EXPLOSION | P_EXPLOSION_FIRST_STAGE, "NUTEXPLOSION1", 0, 360, 360, 360, 280 },    // has ckdelay
+  { O_NUT_EXPL_2, N_("Nut explosion (2)"), P_SLOPED | P_EXPLOSION, "NUTEXPLOSION2", 0, 361, 361, 361, 280 },    /* has ckdelay */        /* these are rounded!! */
+  { 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_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_UNKNOWN, N_("Unknown element"), P_NON_EXPLODABLE, "UNKNOWN", 0, i_unknown, i_unknown, 4 },
+  { O_NONE, N_("No element"), 0, "NONE", 0, 79, 79, 79 },
+  { O_MAX },
+
+  // these are just helpers, for all the element -> image index information to be in this array
+  { O_FAKE_BONUS, NULL, 0, NULL, 0, 120, -120, -120 },
+  { O_INBOX_CLOSED, NULL, 0, NULL, 0, 22, 22, 22 },
+  { O_INBOX_OPEN, NULL, 0, NULL, 0, 23, 23, 23 },
+
+  // game graphics
+  // also for imported diego effects, but don't know if it is used anywhere in original games
+  { 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_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_PUSH_LEFT, N_("Player, pushing left"), P_PLAYER, NULL, 0, 392, -392, -392 },
+  { O_PLAYER_PUSH_RIGHT, N_("Player, pushing right"), P_PLAYER, NULL, 0, 400, -400, -400 },
+  { O_CREATURE_SWITCH_ON, NULL, 0, NULL, 0, 19, 19, 19 },
+  { O_EXPANDING_WALL_SWITCH_HORIZ, NULL, 0, NULL, 0, 40, 40, 40 },
+  { O_EXPANDING_WALL_SWITCH_VERT, NULL, 0, NULL, 0, 41, 41, 41 },
+  { O_GRAVITY_SWITCH_ACTIVE, NULL, 0, NULL, 0, 275, 275, 275 },
+  { O_REPLICATOR_SWITCH_ON, NULL, 0, NULL, 0, 290, 290, 290 },
+  { O_REPLICATOR_SWITCH_OFF, NULL, 0, NULL, 0, 291, 291, 291 },
+  { O_CONVEYOR_DIR_NORMAL, NULL, 0, NULL, 0, 353, 353, 353 },
+  { O_CONVEYOR_DIR_CHANGED, NULL, 0, NULL, 0, 354, 354, 354 },
+  { O_CONVEYOR_SWITCH_OFF, NULL, 0, NULL, 0, 355, 355, 355 },
+  { O_CONVEYOR_SWITCH_ON, NULL, 0, NULL, 0, 356, 356, 356 },
+
+  { O_MAGIC_WALL_ACTIVE, NULL, 0, NULL, 0, 184, -184, -184 },
+  { O_REPLICATOR_ACTIVE, NULL, 0, NULL, 0, 304, -304, -304 },
+  { O_CONVEYOR_LEFT_ACTIVE, NULL, 0, NULL, 0, i_conveyor_left, -328, -328 },
+  { O_CONVEYOR_RIGHT_ACTIVE, NULL, 0, NULL, 0, i_conveyor_right, -320, -320  },
+  { O_BITER_SWITCH_1, NULL, 0, NULL, 0, 12, 12, 12 },
+  { O_BITER_SWITCH_2, NULL, 0, NULL, 0, 13, 13, 13 },
+  { O_BITER_SWITCH_3, NULL, 0, NULL, 0, 14, 14, 14 },
+  { O_BITER_SWITCH_4, NULL, 0, NULL, 0, 15, 15, 15 },
+
+  { O_QUESTION_MARK, NULL, 0, NULL, 0, 70, 70, 70 },
+  { O_EATABLE, NULL, 0, NULL, 0, 71, 71, 71 },
+  { O_DOWN_ARROW, NULL, 0, NULL, 0, 73, 73, 73 },
+  { O_LEFTRIGHT_ARROW, NULL, 0, NULL, 0, 74, 74, 74 },
+  { O_EVERYDIR_ARROW, NULL, 0, NULL, 0, 75, 75, 75 },
+  { O_GLUED, NULL, 0, NULL, 0, 76, 76, 76 },
+  { O_OUT, NULL, 0, NULL, 0, 77, 77, 77 },
+  { O_EXCLAMATION_MARK, NULL, 0, NULL, 0, 78, 78, 78 },
+
+  { -1 },
+};
+
+// entries.
+/* type given for each element;
+ * GD_TYPE_ELEMENT represents a combo box of gdash objects.
+ * GD_TAB&LABEL represents a notebook tab or a label.
+ * others are self-explanatory.
+ */
+const GdStructDescriptor gd_cave_properties[] =
+{
+  // default data
+  {"", GD_TAB, 0, N_("Cave data")},
+  {"Name", GD_TYPE_STRING, 0, N_("Name"), STRUCT_OFFSET(GdCave, name), 1, N_("Name of game")},
+  {"Description", GD_TYPE_STRING, 0, N_("Description"), STRUCT_OFFSET(GdCave, description), 1, N_("Some words about the game")},
+  {"Author", GD_TYPE_STRING, 0, N_("Author"), STRUCT_OFFSET(GdCave, author), 1, N_("Name of author")},
+  {"Date", GD_TYPE_STRING, 0, N_("Date"), STRUCT_OFFSET(GdCave, date), 1, N_("Date of creation")},
+  {"WWW", GD_TYPE_STRING, 0, N_("WWW"), STRUCT_OFFSET(GdCave, www), 1, N_("Web page or e-mail address")},
+  {"Difficulty", GD_TYPE_STRING, 0, N_("Difficulty"), STRUCT_OFFSET(GdCave, difficulty), 1, N_("Difficulty (informative)")},
+
+  {"Selectable", GD_TYPE_BOOLEAN, 0, N_("Selectable as start"), STRUCT_OFFSET(GdCave, selectable), 1, N_("This sets whether the game can be started at this cave.")},
+  {"Intermission", GD_TYPE_BOOLEAN, GD_ALWAYS_SAVE, N_("Intermission"), STRUCT_OFFSET(GdCave, intermission), 1, N_("Intermission caves are usually small and fast caves, which are not required to be solved. The player will not lose a life if he is not successful. The game always proceeds to the next cave.")},
+  {"IntermissionProperties.instantlife", GD_TYPE_BOOLEAN, 0, N_("   Instant life"), STRUCT_OFFSET(GdCave, intermission_instantlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is reached.")},
+  {"IntermissionProperties.rewardlife", GD_TYPE_BOOLEAN, 0, N_("   Reward life"), STRUCT_OFFSET(GdCave, intermission_rewardlife), 1, N_("If true, an extra life is given to the player, when the intermission cave is successfully finished.")},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Width"), STRUCT_OFFSET(GdCave, w), 1, N_("Width of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Height"), STRUCT_OFFSET(GdCave, h), 1, N_("Height of cave. The standard size for a cave is 40x22, and 20x12 for an intermission."), 12, 128},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, left"), STRUCT_OFFSET(GdCave, x1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, upper"), STRUCT_OFFSET(GdCave, y1), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, right"), STRUCT_OFFSET(GdCave, x2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Size", GD_TYPE_INT, GD_ALWAYS_SAVE|GD_DONT_SHOW_IN_EDITOR, N_("Visible, lower"), STRUCT_OFFSET(GdCave, y2), 1, N_("Visible parts of the cave, upper left and lower right corner."), 0, 127},
+  {"Charset", GD_TYPE_STRING, 0, N_("Character set"), STRUCT_OFFSET(GdCave, charset), 1, N_("Theme used for displaying the game. Not used by GDash.")},
+  {"Fontset", GD_TYPE_STRING, 0, N_("Font set"), STRUCT_OFFSET(GdCave, fontset), 1, N_("Font used during the game. Not used by GDash.")},
+
+  // notes - a tab on its own
+  {"Story", GD_TYPE_LONGSTRING, 0, N_("Story"), STRUCT_OFFSET(GdCave, story), 1, N_("Story for the cave. It will be shown when the cave is played.")},
+
+  // remark - also a tab on its own
+  {"Remark", GD_TYPE_LONGSTRING, 0, N_("Remark"), STRUCT_OFFSET(GdCave, remark), 1, N_("Remark (informative). Can contain supplementary information about the design of the cave. It is not shown during the game, only when the user requests the cave info dialog, so can also contain spoilers and hints.")},
+
+  {"", GD_TAB, 0, N_("Colors")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Border color"), STRUCT_OFFSET(GdCave, colorb), 1, N_("Border color for C64 graphics. Only for compatibility, not used by GDash.")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Background color"), STRUCT_OFFSET(GdCave, color0), 1, N_("Background color for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 1 (dirt)"), STRUCT_OFFSET(GdCave, color1), 1, N_("Foreground color 1 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 2 (steel wall)"), STRUCT_OFFSET(GdCave, color2), 1, N_("Foreground color 2 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Color 3 (brick wall)"), STRUCT_OFFSET(GdCave, color3), 1, N_("Foreground color 3 for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Amoeba color"), STRUCT_OFFSET(GdCave, color4), 1, N_("Amoeba color for C64 graphics")},
+  {"Colors", GD_TYPE_COLOR, GD_ALWAYS_SAVE, N_("Slime color"), STRUCT_OFFSET(GdCave, color5), 1, N_("Slime color for C64 graphics")},
+
+  // difficulty
+  {"", GD_TAB, 0, N_("Difficulty")},
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Diamonds")},
+  {"DiamondsRequired", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Diamonds needed"), CAVE_OFFSET(level_diamonds[0]), 5, N_("Here zero means automatically count diamonds before level start. If negative, the value is subtracted from that. This is useful for totally random caves."), -100, 999},
+  {"DiamondValue", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Score for diamonds"), CAVE_OFFSET(diamond_value), 1, N_("Number of points per diamond collected, before opening the exit."), 0, 100},
+  {"DiamondValue", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Score for extra diamonds"), CAVE_OFFSET(extra_diamond_value), 1, N_("Number of points per diamond collected, after opening the exit."), 0, 100},
+  {"", GD_LABEL, 0, N_("Time")},
+  {"CaveTime", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Time (s)"), CAVE_OFFSET(level_time[0]), 5, N_("Time available to solve cave, in seconds."), 1, 999},
+  {"CaveMaxTime", GD_TYPE_INT, 0, N_("Maximum time (s)"), CAVE_OFFSET(max_time), 1, N_("If you reach this time by collecting too many clocks, the timer will overflow."), 60, 999},
+  {"TimeValue", GD_TYPE_INT, 0, N_("Score for time"), CAVE_OFFSET(level_timevalue[0]), 5, N_("Points for each seconds remaining, when the player exits the level."), 0, 50},
+  {"CaveScheduling", GD_TYPE_SCHEDULING, GD_ALWAYS_SAVE, N_("Scheduling type"), CAVE_OFFSET(scheduling), 1, N_("This flag sets whether the game uses an emulation of the original timing (c64-style), or a more modern milliseconds-based timing. The original game used a delay (empty loop) based timing of caves; this is selected by setting this to BD1, BD2, Construction Kit or Crazy Dream 7. This is a compatibility setting only; milliseconds-based timing is recommended for every new cave.")},
+  {"PALTiming", GD_TYPE_BOOLEAN, 0, N_("PAL timing"), CAVE_OFFSET(pal_timing), 1, N_("On the PAL version of the C64 computer, the timer was actually slower than normal seconds. This flag is used to compensate for this. If enabled, one game second will last 1.2 real seconds. Most original games were authored for the PAL version. This is a compatibility setting for imported caves; it is not recommended to enable it for newly authored ones.")},
+  {"FrameTime", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("   Speed (ms)"), CAVE_OFFSET(level_speed[0]), 5, N_("Number of milliseconds between game frames. Used when milliseconds-based timing is active, ie. C64 scheduling is off."), 50, 500},
+  {"HatchingDelay", GD_TYPE_INT, 0, N_("   Hatching delay (frames)"), CAVE_OFFSET(level_hatching_delay_frame[0]), 5, N_("This value sets how much the cave will move until the player enters the cave, and is expressed in frames. This is used for the milliseconds-based scheduling."), 1, 40},
+  {"CaveDelay", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("   Delay (C64-style)"), CAVE_OFFSET(level_ckdelay[0]), 5, N_("The length of the delay loop between game frames. Used when milliseconds-based timing is inactive, ie. some kind of C64 or Atari scheduling is selected."), 0, 32},
+  {"HatchingTime", GD_TYPE_INT, 0, N_("   Hatching time (seconds)"), CAVE_OFFSET(level_hatching_delay_time[0]), 5, N_("This value sets how much the cave will move until the player enters the cave. This is used for the C64-like schedulings."), 1, 40},
+
+  // initial fill
+  {"RandSeed", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* random seed value */, CAVE_OFFSET(level_rand[0]), 5, NULL, -1, 255},
+  {"InitialBorder", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Initial border */, CAVE_OFFSET(initial_border), 1, NULL},
+  {"InitialFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Initial fill */, CAVE_OFFSET(initial_fill), 1, NULL},
+  {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 1 */, CAVE_OFFSET(random_fill[0]), 1, NULL},
+  {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 1 */, CAVE_OFFSET(random_fill_probability[0]), 1, NULL, 0, 255},
+  {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 2 */, CAVE_OFFSET(random_fill[1]), 1, NULL},
+  {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 2 */, CAVE_OFFSET(random_fill_probability[1]), 1, NULL, 0, 255},
+  {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 3 */, CAVE_OFFSET(random_fill[2]), 1, NULL},
+  {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 3 */, CAVE_OFFSET(random_fill_probability[2]), 1, NULL, 0, 255},
+  {"RandomFill", GD_TYPE_ELEMENT, GD_DONT_SHOW_IN_EDITOR, NULL /* Random fill 4 */, CAVE_OFFSET(random_fill[3]), 1, NULL},
+  {"RandomFill", GD_TYPE_INT, GD_DONT_SHOW_IN_EDITOR, NULL /* Probability 4 */, CAVE_OFFSET(random_fill_probability[3]), 1, NULL, 0, 255},
+
+  // PLAYER
+  {"", GD_TAB, 0, N_("Player")},
+
+  // player
+  {"", GD_LABEL, 0, N_("Player movements")},
+  {"DiagonalMovement", GD_TYPE_BOOLEAN, 0, N_("Diagonal movements"), CAVE_OFFSET(diagonal_movements), 1, N_("Controls if the player can move diagonally.")},
+  {"ActiveGuyIsFirst", GD_TYPE_BOOLEAN, 0, N_("Uppermost player active"), CAVE_OFFSET(active_is_first_found), 1, N_("In 1stB, cave is scrolled to the uppermost and leftmost player found, whereas in the original game to the last one. Chasing stones also follow the active player.")},
+  {"SnapEffect", GD_TYPE_ELEMENT, 0, N_("Snap element"), CAVE_OFFSET(snap_element), 1, N_("Snapping (pressing fire while moving) usually creates space, but it can create any other element.")},
+  {"PushingBoulderProb", GD_TYPE_PROBABILITY, 0, N_("Probability of pushing (%)"), CAVE_OFFSET(pushing_stone_prob), 1, N_("Chance of player managing to push a stone, every game cycle he tries. This is the normal probability.")},
+  {"", GD_LABEL, 0, N_("Sweet")},
+  {"PushingBoulderProb", GD_TYPE_PROBABILITY, 0, N_("Probability of pushing (%)"), CAVE_OFFSET(pushing_stone_prob_sweet), 1, N_("Chance of player managing to push a stone, every game cycle he tries. This is used after eating sweet.")},
+  {"PushingMegaStonesAfterSweet", GD_TYPE_BOOLEAN, 0, N_("Mega stones pushable"), CAVE_OFFSET(mega_stones_pushable_with_sweet), 1, N_("If it is true, mega stones can be pushed after eating sweet.")},
+
+  // rocket launcher
+  {"", GD_LABEL, 0, N_("Rocket launcher")},
+  {"RocketLauncher.infinite", GD_TYPE_BOOLEAN, 0, N_("Infinite rockets"), CAVE_OFFSET(infinite_rockets), 1, N_("If it is true, the player is able to launch an infinite number of rockets. Otherwise every rocket launcher contains only a single rocket.")},
+
+  // pneumatic hammer
+  {"", GD_LABEL, 0, N_("Pneumatic hammer")},
+  {"PneumaticHammer.frames", GD_TYPE_INT, 0, N_("Time for hammer (frames)"), CAVE_OFFSET(pneumatic_hammer_frame), 1, N_("This is the number of game frames, a pneumatic hammer is required to break a wall."), 1, 100},
+  {"PneumaticHammer.wallsreappear", GD_TYPE_BOOLEAN, 0, N_("Hammered walls reappear"), CAVE_OFFSET(hammered_walls_reappear), 1, N_("If this is set to true, walls broken with a pneumatic hammer will reappear later.")},
+  {"PneumaticHammer.wallsreappearframes", GD_TYPE_INT, 0, N_("   Timer for reappear (frames)"), CAVE_OFFSET(hammered_wall_reappear_frame), 1, N_("This sets the number of game frames, after hammered walls reappear, when the above setting is true."), 1, 200},
+
+  // clock
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Clock")},
+  {"BonusTime", GD_TYPE_INT, 0, N_("Time bonus (s)"), CAVE_OFFSET(level_bonus_time), 5, N_("Bonus time when a clock is collected."), -100, 100},
+
+  // voodoo
+  {"", GD_LABEL, 0, N_("Voodoo Doll")},
+  {"DummyProperties.diamondcollector", GD_TYPE_BOOLEAN, 0, N_("Can collect diamonds"), CAVE_OFFSET(voodoo_collects_diamonds), 1, N_("Controls if a voodoo doll can collect diamonds for the player.")},
+  {"DummyProperties.penalty", GD_TYPE_BOOLEAN, 0, N_("Dies if hit by a stone"), CAVE_OFFSET(voodoo_dies_by_stone), 1, N_("Controls if the voodoo doll dies if it is hit by a stone. Then the player gets a time penalty, and it is turned to a gravestone surrounded by steel wall.")},
+  {"DummyProperties.destructable", GD_TYPE_BOOLEAN, 0, N_("Disappear in explosion"), CAVE_OFFSET(voodoo_disappear_in_explosion), 1, N_("Controls if the voodoo can be destroyed by an explosion nearby. If not, it is converted to a gravestone, and you get a time penalty. If yes, the voodoo simply disappears.")},
+  {"DummyProperties.alwayskillsplayer", GD_TYPE_BOOLEAN, 0, N_("Any way hurt, player explodes"), CAVE_OFFSET(voodoo_any_hurt_kills_player), 1, N_("If this setting is enabled, the player will explode if the voodoo is hurt in any possible way, ie. touched by a firefly, hit by a stone or an explosion.")},
+  {"PenaltyTime", GD_TYPE_INT, 0, N_("Time penalty (s)"), CAVE_OFFSET(level_penalty_time), 5, N_("Penalty time when the voodoo is destroyed by a stone."), 0, 100},
+
+  // AMOEBA
+  {"", GD_TAB, 0, N_("Amoeba")},
+  {"AmoebaProperties.immediately", GD_TYPE_BOOLEAN, 0, N_("Timer started immediately"), CAVE_OFFSET(amoeba_timer_started_immediately), 1, N_("If this flag is enabled, the amoeba slow growth timer will start at the beginning of the cave, regardless of the amoeba being let free or not. This can make a big difference when playing the cave!")},
+  {"AmoebaProperties.waitforhatching", GD_TYPE_BOOLEAN, 0, N_("Timer waits for hatching"), CAVE_OFFSET(amoeba_timer_wait_for_hatching), 1, N_("This determines if the amoeba timer starts before the player appearing. Amoeba can always be activated before that; but if this is set to true, the timer will not start. This setting is for compatiblity for some old imported caves. As the player is usually born within a few seconds, changing this setting makes not much difference. It is not advised to change it, set the slow growth time to fit your needs instead.")},
+
+  // amoeba
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Amoeba")},
+  {"AmoebaThreshold", GD_TYPE_RATIO, 0, N_("Threshold (cells)"), CAVE_OFFSET(level_amoeba_threshold), 5, N_("If the amoeba grows more than this fraction of the cave, it is considered too big and it converts to the element specified below."), 0, 16383},
+  {"AmoebaTime", GD_TYPE_INT, 0, N_("Slow growth time (s)"), CAVE_OFFSET(level_amoeba_time), 5, N_("After this time, amoeba will grow very quickly."), 0, 999},
+  {"AmoebaGrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, slow (%)"), CAVE_OFFSET(amoeba_growth_prob), 1, N_("This sets the speed at which a slow amoeba grows.")},
+  {"AmoebaGrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, fast (%)"), CAVE_OFFSET(amoeba_fast_growth_prob), 1, N_("This sets the speed at which a fast amoeba grows.")},
+  {"AMOEBABOULDEReffect", GD_TYPE_EFFECT, 0, N_("If too big, converts to"), CAVE_OFFSET(amoeba_too_big_effect), 1, N_("Controls which element an overgrown amoeba converts to.")},
+  {"AMOEBADIAMONDeffect", GD_TYPE_EFFECT, 0, N_("If enclosed, converts to"), CAVE_OFFSET(amoeba_enclosed_effect), 1, N_("Controls which element an enclosed amoeba converts to.")},
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Amoeba 2")},
+  {"Amoeba2Threshold", GD_TYPE_RATIO, 0, N_("Threshold (cells)"), CAVE_OFFSET(level_amoeba_2_threshold), 5, N_("If the amoeba grows more than this fraction of the cave, it is considered too big and it converts to the element specified below."), 0, 16383},
+  {"Amoeba2Time", GD_TYPE_INT, 0, N_("Slow growth time (s)"), CAVE_OFFSET(level_amoeba_2_time), 5, N_("After this time, amoeba will grow very quickly."), 0, 999},
+  {"Amoeba2GrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, slow (%)"), CAVE_OFFSET(amoeba_2_growth_prob), 1, N_("This sets the speed at which a slow amoeba grows.")},
+  {"Amoeba2GrowthProb", GD_TYPE_PROBABILITY, 0, N_("Growth ratio, fast (%)"), CAVE_OFFSET(amoeba_2_fast_growth_prob), 1, N_("This sets the speed at which a fast amoeba grows.")},
+  {"Amoeba2Properties.explode", GD_TYPE_BOOLEAN, 0, N_("Explodes by amoeba"), CAVE_OFFSET(amoeba_2_explodes_by_amoeba), 1, N_("If this setting is enabled, an amoeba 2 will explode if it is touched by a normal amoeba.")},
+  {"AMOEBA2EXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_("   Explosion ends in"), CAVE_OFFSET(amoeba_2_explosion_effect), 1, N_("An amoeba 2 explodes to this element, when touched by the original amoeba.")},
+  {"AMOEBA2BOULDEReffect", GD_TYPE_EFFECT, 0, N_("If too big, converts to"), CAVE_OFFSET(amoeba_2_too_big_effect), 1, N_("Controls which element an overgrown amoeba converts to.")},
+  {"AMOEBA2DIAMONDeffect", GD_TYPE_EFFECT, 0, N_("If enclosed, converts to"), CAVE_OFFSET(amoeba_2_enclosed_effect), 1, N_("Controls which element an enclosed amoeba converts to.")},
+  {"AMOEBA2LOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Looks like"), CAVE_OFFSET(amoeba_2_looks_like), 1, N_("Amoeba 2 can look like any other element. Hint: it can also look like a normal amoeba. Or it can look like slime, and then you have two different colored amoebas!")},
+
+  // magic wall
+  {"", GD_TAB, 0, N_("Magic Wall")},
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Timing")},
+  {"MagicWallTime", GD_TYPE_INT, 0, N_("Milling time (s)"), CAVE_OFFSET(level_magic_wall_time), 5, N_("Magic wall will stop after this time, and it cannot be activated again."), 0, 999},
+  {"MagicWallProperties.zeroisinfinite", GD_TYPE_BOOLEAN, 0, N_("Milling time 0 is infinite"), CAVE_OFFSET(magic_timer_zero_is_infinite), 1, N_("This determines if the magic wall timer 0 is interpreted as infinite.")},
+  {"MagicWallProperties.waitforhatching", GD_TYPE_BOOLEAN, 0, N_("Timer waits for hatching"), CAVE_OFFSET(magic_timer_wait_for_hatching), 1, N_("This determines if the magic wall timer starts before the player appearing. Magic can always be activated before that; but if this is set to true, the timer will not start.")},
+  {"MagicWallProperties.convertamoeba", GD_TYPE_BOOLEAN, 0, N_("Stops amoeba"), CAVE_OFFSET(magic_wall_stops_amoeba), 1, N_("When the magic wall is activated, it can convert amoeba into diamonds.")},
+  {"MagicWallProperties.breakscan", GD_TYPE_BOOLEAN, 0, N_("BD1 amoeba bug"), CAVE_OFFSET(magic_wall_breakscan), 1, N_("This setting emulates the BD1 bug, where a stone or a diamond falling into a magic wall sometimes caused the active amoeba to convert into a diamond. The rule is: if all amoeba cells above or left to the point where the stone or the diamond falls into the magic wall are enclosed, the amoeba is converted. The timing implications of the bug are not emulated.")},
+  {"", GD_LABEL, 0, N_("Conversions")},
+  {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Diamond to"), CAVE_OFFSET(magic_diamond_to), 1, N_("As a special effect, magic walls can convert diamonds to any other element.")},
+  {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Stone to"), CAVE_OFFSET(magic_stone_to), 1, N_("As a special effect, magic walls can convert stones to any other element.")},
+  {"MagicWallProperties.megastoneto", GD_TYPE_ELEMENT, 0, N_("Mega stone to"), CAVE_OFFSET(magic_mega_stone_to), 1, N_("If a mega stone falls into the magic wall, it will drop this element.")},
+  {"MagicWallProperties.nitropackto", GD_TYPE_ELEMENT, 0, N_("Nitro pack to"), CAVE_OFFSET(magic_nitro_pack_to), 1, N_("If a nitro pack falls into the magic wall, it will be turned to this element.")},
+  {"MagicWallProperties.nutto", GD_TYPE_ELEMENT, 0, N_("Nut to"), CAVE_OFFSET(magic_nut_to), 1, N_("As a special effect, magic walls can convert nuts to any other element.")},
+  {"MagicWallProperties.flyingstoneto", GD_TYPE_ELEMENT, 0, N_("Flying stone to"), CAVE_OFFSET(magic_flying_stone_to), 1, N_("If a flying stone climbs up into the magic wall, it will be turned to this element. Remember that flying stones enter the magic wall from its bottom, not from the top!")},
+  {"MagicWallProperties.flyingdiamondto", GD_TYPE_ELEMENT, 0, N_("Flying diamonds to"), CAVE_OFFSET(magic_flying_diamond_to), 1, N_("If a flying diamond enters the magic wall, it will be turned to this element. Remember that flying diamonds enter the magic wall from its bottom, not from the top!")},
+
+  // slime
+  {"", GD_TAB, 0, N_("Slime")},
+  {"", GD_LABEL, GD_SHOW_LEVEL_LABEL, N_("Permeability")},
+  {"", GD_TYPE_BOOLEAN, GD_DONT_SAVE, N_("Predictable"), CAVE_OFFSET(slime_predictable), 1, N_("Controls if the predictable random generator is used for slime. It is required for compatibility with some older caves.")},
+
+  // permeabilities are "always" saved; and according to the predictability, one of them is removed.
+  {"SlimePermeability", GD_TYPE_PROBABILITY, GD_ALWAYS_SAVE, N_("Permeability (unpredictable, %)"), CAVE_OFFSET(level_slime_permeability[0]), 5, N_("This controls the rate at which elements go through the slime. Higher values represent higher probability of passing. This one is for unpredictable slime.")},
+  {"SlimePermeabilityC64", GD_TYPE_INT, GD_ALWAYS_SAVE, N_("Permeability (predictable, bits)"), CAVE_OFFSET(level_slime_permeability_c64[0]), 5, N_("This controls the rate at which elements go through the slime. This one is for predictable slime, and the value is used for a bitwise AND function. The values used by the C64 engines are 0, 128, 192, 224, 240, 248, 252, 254 and 255."), 0, 255},
+  {"SlimePredictableC64.seed", GD_TYPE_INT, 0, N_("Random seed (predictable)"), CAVE_OFFSET(level_slime_seed_c64), 5, N_("The random number seed for predictable slime. Use -1 to leave on its default. Not recommended to change. Does not affect unpredictable slime."), -1, 65535},
+  {"", GD_LABEL, 0, N_("Passing elements")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("Eats this..."), CAVE_OFFSET(slime_eats_1), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("  ... and converts to"), CAVE_OFFSET(slime_converts_1), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("Eats this..."), CAVE_OFFSET(slime_eats_2), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("  ... and converts to"), CAVE_OFFSET(slime_converts_2), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("Eats this..."), CAVE_OFFSET(slime_eats_3), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+  {"SlimeProperties", GD_TYPE_ELEMENT, 0, N_("  ... and converts to"), CAVE_OFFSET(slime_converts_3), 1, N_("Slime can let other elements than stone and diamond go through. It always lets a waiting or a chasing stone pass, though. Also, flying diamonds and stones, as well as bladders are always passed.")},
+
+  // ACTIVE 2
+  {"", GD_TAB, 0, N_("Other elements")},
+
+  // acid
+  {"", GD_LABEL, 0, N_("Acid")},
+  {"AcidProperties", GD_TYPE_ELEMENT, 0, N_("Eats this element"), CAVE_OFFSET(acid_eats_this), 1, N_("The element which acid eats. If it cannot find any, it simply disappears.")},
+  {"AcidProperties", GD_TYPE_PROBABILITY, 0, N_("Spread ratio (%)"), CAVE_OFFSET(acid_spread_ratio), 1, N_("The probability at which an acid will explode and eat neighbouring elements.")},
+  {"ACIDEffect", GD_TYPE_EFFECT, 0, N_("Leaves this behind"), CAVE_OFFSET(acid_turns_to), 1, N_("If acid converts to an explosion puff on spreading or any other element.")},
+
+  // biter
+  {"", GD_LABEL, 0, N_("Biter")},
+  {"BiterProperties", GD_TYPE_INT, 0, N_("Delay (frame)"), CAVE_OFFSET(biter_delay_frame), 1, N_("Number of frames biters wait between movements."), 0, 3},
+  {"BiterProperties", GD_TYPE_ELEMENT, 0, N_("Eats this"), CAVE_OFFSET(biter_eat), 1, N_("Biters eat this element. (They always eat dirt.)")},
+
+  // bladder
+  {"", GD_LABEL, 0, N_("Bladder")},
+  {"BladderProperties", GD_TYPE_ELEMENT, 0, N_("Converts to clock by touching"), CAVE_OFFSET(bladder_converts_by), 1, NULL},
+
+  // expanding wall
+  {"", GD_LABEL, 0, N_("Expanding wall")},
+  {"ExpandingWallDirection.changed", GD_TYPE_BOOLEAN, 0, N_("Direction changed"), CAVE_OFFSET(expanding_wall_changed), 1, N_("If this option is enabled, the direction of growing for the horizontal and vertical expanding wall is switched. As you can use both horizontal and vertical expanding walls in a cave, it is not recommended to change this setting, as it might be confusing. You should rather select the type with the correct direction from the element box when drawing the cave.")},
+
+  // replicator
+  {"", GD_LABEL, 0, N_("Replicator")},
+  {"ReplicatorActive", GD_TYPE_BOOLEAN, 0, N_("Active at start"), CAVE_OFFSET(replicators_active), 1, N_("Whether the replicators are turned on or off at the cave start.")},
+  {"ReplicatorDelayFrame", GD_TYPE_INT, 0, N_("Delay (frame)"), CAVE_OFFSET(replicator_delay_frame), 1, N_("Number of frames to wait between replicating elements."), 0, 100},
+
+  // conveyor belt
+  {"", GD_LABEL, 0, N_("Conveyor belt")},
+  {"ConveyorBeltActive", GD_TYPE_BOOLEAN, 0, N_("Active at start"), CAVE_OFFSET(conveyor_belts_active), 1, N_("Whether the conveyor belts are moving when the cave starts.")},
+  {"ConveyorBeltDirection.changed", GD_TYPE_BOOLEAN, 0, N_("Direction changed"), CAVE_OFFSET(conveyor_belts_direction_changed), 1, N_("If the conveyor belts' movement is changed, ie. they are running in the opposite direction. As you can freely use left and right going versions of the conveyor belt in a cave, it is not recommended to change this setting, rather you should select the correct one from the element box when drawing.")},
+
+  // water
+  {"", GD_LABEL, 0, N_("Water")},
+  {"WaterProperties.doesnotflowdown", GD_TYPE_BOOLEAN, 0, N_("Does not flow downwards"), CAVE_OFFSET(water_does_not_flow_down), 1, N_("In CrDr, the water element had the odd property that it did not flow downwards, only in other directions. This flag emulates this behaviour.")},
+
+  // nut
+  {"", GD_LABEL, 0, N_("Nut")},
+  {"Nut.whencrushed", GD_TYPE_ELEMENT, 0, N_("Turns to when crushed"), CAVE_OFFSET(nut_turns_to_when_crushed), 1, N_("Normally, a nut contains a diamond. If you crush it with a stone, the diamond will appear after the usual nut explosion sequence. This setting can be used to change the element the nut contains.")},
+
+  // EFFECTS 1
+  {"", GD_TAB, 0, N_("Effects")},
+
+  // cave effects
+  {"", GD_LABEL, 0, N_("Stone and diamond effects")},
+  {"BOULDERfallingeffect", GD_TYPE_EFFECT, 0, N_("Falling stones convert to"), CAVE_OFFSET(stone_falling_effect), 1, N_("When a stone begins falling, it converts to this element.")},
+  {"BOULDERbouncingeffect", GD_TYPE_EFFECT, 0, N_("Bouncing stones convert to"), CAVE_OFFSET(stone_bouncing_effect), 1, N_("When a stone stops falling and rolling, it converts to this element.")},
+  {"DIAMONDfallingeffect", GD_TYPE_EFFECT, 0, N_("Falling diamonds convert to"), CAVE_OFFSET(diamond_falling_effect), 1, N_("When a diamond begins falling, it converts to this element.")},
+  {"DIAMONDbouncingeffect", GD_TYPE_EFFECT, 0, N_("Bouncing diamonds convert to"), CAVE_OFFSET(diamond_bouncing_effect), 1, N_("When a diamond stops falling and rolling, it converts to this element.")},
+
+  {"", GD_LABEL, 0, N_("Creature explosion effects")},
+  {"FireflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Fireflies explode to"), CAVE_OFFSET(firefly_explode_to), 1, N_("When a firefly explodes, it will create this element. Change this setting wisely. The firefly is a traditional element which is expected to explode to empty space.")},
+  {"AltFireflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Alt. fireflies explode to"), CAVE_OFFSET(alt_firefly_explode_to), 1, N_("When an alternative firefly explodes, it will create this element. Use this setting wisely. Do not create a firefly which explodes to stones, for example: use the stonefly instead.")},
+  {"ButterflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Butterflies explode to"), CAVE_OFFSET(butterfly_explode_to), 1, N_("When a butterfly explodes, it will create this element. Use this setting wisely. Butterflies should explode to diamonds. If you need a creature which explodes to space, use the firefly instead.")},
+  {"AltButterflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Alt. butterflies explode to"), CAVE_OFFSET(alt_butterfly_explode_to), 1, N_("When an alternative butterfly explodes, it will create this element. Use this setting wisely.")},
+  {"StoneflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Stoneflies explode to"), CAVE_OFFSET(stonefly_explode_to), 1, N_("When a stonefly explodes, it will create this element.")},
+  {"DragonflyExplodeTo", GD_TYPE_ELEMENT, 0, N_("Dragonflies explode to"), CAVE_OFFSET(dragonfly_explode_to), 1, N_("When a dragonfly explodes, it will create this element.")},
+
+  {"", GD_LABEL, 0, N_("Explosion effects")},
+  {"EXPLOSIONEffect", GD_TYPE_EFFECT, 0, N_("Explosions end in"), CAVE_OFFSET(explosion_effect), 1, N_("This element appears in places where an explosion finishes.")},
+  {"DIAMONDBIRTHEffect", GD_TYPE_EFFECT, 0, N_("Diamond births end in"), CAVE_OFFSET(diamond_birth_effect), 1, N_("When a diamond birth animation reaches its end, it will leave this element there. This can be used to change the element butterflies explode to.")},
+  {"BOMBEXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_("Bombs explosions end in"), CAVE_OFFSET(bomb_explosion_effect), 1, N_("Use this setting to select the element the exploding bomb creates.")},
+  {"NITROEXPLOSIONeffect", GD_TYPE_EFFECT, 0, N_("Nitro explosions end in"), CAVE_OFFSET(nitro_explosion_effect), 1, N_("The nitro explosions can create some element other than space.")},
+
+  // EFFECTS 2
+  {"", GD_TAB, 0, N_("More effects")},
+
+  // visual effects
+  {"", GD_LABEL, 0, N_("Visual effects")},
+  {"EXPANDINGWALLLOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Expanding wall looks like"), CAVE_OFFSET(expanding_wall_looks_like), 1, N_("This is a compatibility setting for old caves. If you need an expanding wall which looks like steel, you should rather choose the expanding steel wall from the element box.")},
+  {"DIRTLOOKSLIKEeffect", GD_TYPE_EFFECT, 0, N_("Dirt looks like"), CAVE_OFFSET(dirt_looks_like), 1, N_("Compatibility setting. Use it wisely! Anything other than Dirt 2 (which can be used to emulate the Dirt Mod) is not recommended.")},
+
+  // creature effects
+  {"", GD_LABEL, 0, N_("Creature movement")},
+  {"EnemyDirectionProperties.startbackwards", GD_TYPE_BOOLEAN, 0, N_("Start backwards"), CAVE_OFFSET(creatures_backwards), 1, N_("Whether the direction creatures travel will already be switched at the cave start.")},
+  {"EnemyDirectionProperties.time", GD_TYPE_INT, 0, N_("Automatically turn (s)"), CAVE_OFFSET(creatures_direction_auto_change_time), 1, N_("If this is greater than zero, creatures will automatically change direction in every x seconds."), 0, 999},
+  {"EnemyDirectionProperties.changeathatching", GD_TYPE_BOOLEAN, 0, N_("Auto turn on hatching"), CAVE_OFFSET(creatures_direction_auto_change_on_start), 1, N_("If this is set to true, creatures also turn at the start signal. If false, the first change in direction occurs only later.")},
+
+  // gravity
+  {"", GD_LABEL, 0, N_("Gravitation change")},
+  {"Gravitation", GD_TYPE_DIRECTION, 0, N_("Direction"), CAVE_OFFSET(gravity), 1, N_("The direction where stones and diamonds fall.")},
+  {"GravitationSwitchActive", GD_TYPE_BOOLEAN, 0, N_("Switch active at start"), CAVE_OFFSET(gravity_switch_active), 1, N_("If set to true, the gravitation switch will be already activated, when the cave is started, as if a pot has already been collected.")},
+  {"SkeletonsForPot", GD_TYPE_INT, 0, N_("Skeletons needed for pot"), CAVE_OFFSET(skeletons_needed_for_pot), 1, N_("The number of skeletons to be collected to be able to use a pot."), 0, 50},
+  {"GravitationChangeDelay", GD_TYPE_INT, 0, N_("Gravitation switch delay"), CAVE_OFFSET(gravity_change_time), 1, N_("The gravitation changes after a while using the gravitation switch. This option sets the number of seconds to wait."), 1, 60},
+
+  // SOUND
+  {"", GD_TAB, 0, N_("Sound")},
+  {"", GD_LABEL, 0, N_("Sound for elements")},
+  {"Diamond.sound", GD_TYPE_BOOLEAN, 0, N_("Diamond"), CAVE_OFFSET(diamond_sound), 1, N_("If true, falling diamonds will have sound.")},
+  {"Stone.sound", GD_TYPE_BOOLEAN, 0, N_("Stone"), CAVE_OFFSET(stone_sound), 1, N_("If true, falling and pushed stones will have sound.")},
+  {"Nut.sound", GD_TYPE_BOOLEAN, 0, N_("Nut"), CAVE_OFFSET(nut_sound), 1, N_("If true, falling and cracked nuts have sound.")},
+  {"NitroPack.sound", GD_TYPE_BOOLEAN, 0, N_("Nitro pack"), CAVE_OFFSET(nitro_sound), 1, N_("If true, falling and pushed nitro packs will have sound.")},
+  {"ExpandingWall.sound", GD_TYPE_BOOLEAN, 0, N_("Expanding wall"), CAVE_OFFSET(expanding_wall_sound), 1, N_("If true, expanding wall will have sound.")},
+  {"FallingWall.sound", GD_TYPE_BOOLEAN, 0, N_("Falling wall"), CAVE_OFFSET(falling_wall_sound), 1, N_("If true, falling wall will have sound.")},
+  {"AmoebaProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Amoeba"), CAVE_OFFSET(amoeba_sound), 1, N_("Controls if the living amoeba has sound or not.")},
+  {"MagicWallProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Magic wall"), CAVE_OFFSET(magic_wall_sound), 1, N_("If true, the activated magic wall will have sound.")},
+  {"SlimeProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Slime"), CAVE_OFFSET(slime_sound), 1, N_("If true, the elements passing slime will have sound.")},
+  {"LavaProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Lava"), CAVE_OFFSET(lava_sound), 1, N_("If true, the elements sinking in lava will have sound.")},
+  {"ReplicatorProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Replicator"), CAVE_OFFSET(replicator_sound), 1, N_("If true, the new element appearing under the replicator will make sound.")},
+  {"AcidProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Acid"), CAVE_OFFSET(acid_spread_sound), 1, N_("If true, the acid spreading will have sound.")},
+  {"BiterProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Biter"), CAVE_OFFSET(biter_sound), 1, N_("Biters eating something or pushing a stone will have sound.")},
+  {"BladderProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder"), CAVE_OFFSET(bladder_sound), 1, N_("Bladders moving and being pushed can have sound.")},
+  {"WaterProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Water"), CAVE_OFFSET(water_sound), 1, N_("If true, the cave containing water will have sound.")},
+  {"PneumaticHammer.sound", GD_TYPE_BOOLEAN, 0, N_("Pneumatic hammer"), CAVE_OFFSET(pneumatic_hammer_sound), 1, N_("If true, using the pneumatic hammer will have sound.")},
+  {"BladderSpender.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder spender"), CAVE_OFFSET(bladder_spender_sound), 1, N_("If true, the bladder spender will make sound, when the bladder appears.")},
+  {"BladderConvert.sound", GD_TYPE_BOOLEAN, 0, N_("Bladder convert"), CAVE_OFFSET(bladder_convert_sound), 1, N_("If true, the bladder converting to a clock will make sound.")},
+  {"", GD_LABEL, 0, N_("Event sounds")},
+  {"GravityChange.sound", GD_TYPE_BOOLEAN, 0, N_("Gravity change"), CAVE_OFFSET(gravity_change_sound), 1, N_("If true, the gravity changing will make sound.")},
+  {"EnemyDirectionProperties.sound", GD_TYPE_BOOLEAN, 0, N_("Creature direction change"), CAVE_OFFSET(creature_direction_auto_change_sound), 1, N_("If this is set to true, creatures changing direction will be signaled by a sound.")},
+
+  // COMPATIBILITY
+  {"", GD_TAB, 0, N_("Compatibility")},
+  {"", GD_LABEL, 0, N_("Skeleton")},
+  {"SkeletonsWorthDiamonds", GD_TYPE_INT, GD_COMPATIBILITY_SETTING, N_("Skeletons worth diamonds"), CAVE_OFFSET(skeletons_worth_diamonds), 1, N_("The number of diamonds each skeleton is worth. Normally skeletons are used for letting the player use the pot! They are not intended to be used as a second kind of diamond."), 0, 10},
+  {"", GD_LABEL, 0, N_("Borders")},
+  {"BorderProperties.lineshift", GD_TYPE_BOOLEAN, 0, N_("Line shifting border"), CAVE_OFFSET(lineshift), 1, N_("If this is set to true, the player exiting on either side will appear one row lower or upper on the other side.")},
+  {"BorderProperties.objectwraparound", GD_TYPE_BOOLEAN, 0, N_("Objects wrap around"), CAVE_OFFSET(wraparound_objects), 1, N_("If true, objects will wrap around the cave borders as well, ie. if you drag a line to the left, part of it will appear on the right hand side of the cave. The drawing in this case is also affected by the line shifting border property. If that one is enabled, too, crossing the left hand side or right hand side boundary will decrement or increment the row, and crossing the top or the bottom boundary will have no effect at all.")},
+  {"BorderProperties.scan", GD_TYPE_BOOLEAN, 0, N_("Scan first and last row"), CAVE_OFFSET(border_scan_first_and_last), 1, N_("Elements move on first and last row, too. Usually those rows are the border. The games created by the original editor were not allowed to put anything but steel wall there, so it was not apparent that the borders were not processed by the engine. Some old caves need this for compatibility; it is not recommended to change this setting for newly designed caves, though.")},
+  {"", GD_LABEL, 0, N_("Other")},
+  {"ShortExplosions", GD_TYPE_BOOLEAN, 0, N_("Short explosions"), CAVE_OFFSET(short_explosions), 1, N_("In 1stB and newer engines, explosions were longer, they took five cave frames to complete, as opposed to four frames in the original.")},
+  {"GravityAffectsAll", GD_TYPE_BOOLEAN, 0, N_("Gravity change affects everything"), CAVE_OFFSET(gravity_affects_all), 1, N_("If this is enabled, changing the gravity will also affect bladders (moving and pushing), bladder spenders, falling walls and waiting stones. Otherwise, those elements behave as gravity was always pointing downwards. This is a compatibility setting which is not recommended to change. It is intended for imported caves.")},
+
+  {NULL}  // end of array
+};
+
+// entries.
+// type given for each element
+const GdStructDescriptor gd_replay_properties[] =
+{
+  // default data
+  {"", GD_TAB, 0, N_("Replay")},
+  {"Level", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, level), 1, NULL},
+  {"RandomSeed", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, seed), 1, NULL},
+  // {"Saved", GD_TYPE_BOOLEAN, 0, NULL, STRUCT_OFFSET(GdReplay, saved), 1, NULL},
+  // no need to state in bdcff, as saved replays are saved ones :)
+  {"Player", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, player_name), 1, NULL},
+  {"Date", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, date), 1, NULL},
+  {"Comment", GD_TYPE_LONGSTRING, 0, NULL, STRUCT_OFFSET(GdReplay, comment), 1, NULL},
+  {"RecordedWith", GD_TYPE_STRING, 0, NULL, STRUCT_OFFSET(GdReplay, recorded_with), 1, NULL},
+  {"Score", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, score), 1, NULL},
+  {"Duration", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, duration), 1, NULL},
+  {"Success", GD_TYPE_BOOLEAN, 0, NULL, STRUCT_OFFSET(GdReplay, success), 1, NULL},
+  {"Checksum", GD_TYPE_INT, 0, NULL, STRUCT_OFFSET(GdReplay, checksum), 1, NULL},
+
+  {NULL}  // end of array
+};
+
+GdPropertyDefault gd_cave_defaults_gdash[] =
+{
+  // default data
+  {CAVE_OFFSET(selectable), TRUE},
+  {CAVE_OFFSET(intermission), FALSE},
+  {CAVE_OFFSET(intermission_instantlife), FALSE},
+  {CAVE_OFFSET(intermission_rewardlife), TRUE},
+  {CAVE_OFFSET(w), 40},
+  {CAVE_OFFSET(h), 22},
+  {CAVE_OFFSET(x1), 0},
+  {CAVE_OFFSET(y1), 0},
+  {CAVE_OFFSET(x2), 39},
+  {CAVE_OFFSET(y2), 21},
+  {CAVE_OFFSET(colorb), 0},
+  {CAVE_OFFSET(color0), 0},
+  {CAVE_OFFSET(color1), 8},
+  {CAVE_OFFSET(color2), 11},
+  {CAVE_OFFSET(color3), 1},
+  {CAVE_OFFSET(color4), 5},
+  {CAVE_OFFSET(color5), 6},
+
+  // difficulty
+  {CAVE_OFFSET(level_diamonds[0]), 10},
+  {CAVE_OFFSET(diamond_value), 0},
+  {CAVE_OFFSET(extra_diamond_value), 0},
+  {CAVE_OFFSET(level_time[0]), 999},
+  {CAVE_OFFSET(max_time), 999},
+  {CAVE_OFFSET(pal_timing), FALSE},
+  {CAVE_OFFSET(level_timevalue[0]), 1},
+  {CAVE_OFFSET(scheduling), GD_SCHEDULING_MILLISECONDS},
+  {CAVE_OFFSET(level_ckdelay[0]), 0},
+  {CAVE_OFFSET(level_hatching_delay_time[0]), 2},
+  {CAVE_OFFSET(level_speed[0]), 200},
+  {CAVE_OFFSET(level_hatching_delay_frame[0]), 21},
+  {CAVE_OFFSET(level_rand[0]), 0},
+
+  // initial fill
+  {CAVE_OFFSET(initial_border), O_STEEL},
+  {CAVE_OFFSET(initial_fill), O_DIRT},
+  {CAVE_OFFSET(random_fill[0]), O_DIRT},
+  {CAVE_OFFSET(random_fill_probability[0]), 0},
+  {CAVE_OFFSET(random_fill[1]), O_DIRT},
+  {CAVE_OFFSET(random_fill_probability[1]), 0},
+  {CAVE_OFFSET(random_fill[2]), O_DIRT},
+  {CAVE_OFFSET(random_fill_probability[2]), 0},
+  {CAVE_OFFSET(random_fill[3]), O_DIRT},
+  {CAVE_OFFSET(random_fill_probability[3]), 0},
+
+  // PLAYER
+  {CAVE_OFFSET(diagonal_movements), FALSE},
+  {CAVE_OFFSET(active_is_first_found), TRUE},
+  {CAVE_OFFSET(snap_element), O_SPACE},
+  {CAVE_OFFSET(pushing_stone_prob), 250000},
+  {CAVE_OFFSET(pushing_stone_prob_sweet), 1000000},
+  {CAVE_OFFSET(level_bonus_time), 30},
+  {CAVE_OFFSET(pneumatic_hammer_frame), 5},
+  {CAVE_OFFSET(hammered_walls_reappear), FALSE},
+  {CAVE_OFFSET(hammered_wall_reappear_frame), 100},
+  {CAVE_OFFSET(voodoo_collects_diamonds), FALSE},
+  {CAVE_OFFSET(voodoo_disappear_in_explosion), TRUE},
+  {CAVE_OFFSET(voodoo_dies_by_stone), FALSE},
+  {CAVE_OFFSET(voodoo_any_hurt_kills_player), FALSE},
+  {CAVE_OFFSET(level_penalty_time), 30},
+
+  // magic wall
+  {CAVE_OFFSET(level_magic_wall_time), 999},
+  {CAVE_OFFSET(magic_diamond_to), O_STONE_F},
+  {CAVE_OFFSET(magic_stone_to), O_DIAMOND_F},
+  {CAVE_OFFSET(magic_mega_stone_to), O_NITRO_PACK_F},
+  {CAVE_OFFSET(magic_nitro_pack_to), O_MEGA_STONE_F},
+  {CAVE_OFFSET(magic_nut_to), O_NUT_F},
+  {CAVE_OFFSET(magic_flying_stone_to), O_FLYING_DIAMOND_F},
+  {CAVE_OFFSET(magic_flying_diamond_to), O_FLYING_STONE_F},
+  {CAVE_OFFSET(magic_wall_stops_amoeba), TRUE},
+  {CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE},
+  {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
+
+  // amoeba
+  {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
+  {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
+
+  {CAVE_OFFSET(level_amoeba_threshold), 200},
+  {CAVE_OFFSET(amoeba_growth_prob), 31250},
+  {CAVE_OFFSET(amoeba_fast_growth_prob), 250000},
+  {CAVE_OFFSET(level_amoeba_time), 999},
+  {CAVE_OFFSET(amoeba_timer_started_immediately), TRUE},
+  {CAVE_OFFSET(amoeba_timer_wait_for_hatching), FALSE},
+  {CAVE_OFFSET(amoeba_too_big_effect), O_STONE},
+  {CAVE_OFFSET(amoeba_enclosed_effect), O_DIAMOND},
+
+  // amoeba
+  {CAVE_OFFSET(level_amoeba_2_threshold), 200},
+  {CAVE_OFFSET(amoeba_2_growth_prob), 31250},
+  {CAVE_OFFSET(amoeba_2_fast_growth_prob), 250000},
+  {CAVE_OFFSET(level_amoeba_2_time), 999},
+  {CAVE_OFFSET(amoeba_2_too_big_effect), O_STONE},
+  {CAVE_OFFSET(amoeba_2_enclosed_effect), O_DIAMOND},
+  {CAVE_OFFSET(amoeba_2_explodes_by_amoeba), TRUE},
+  {CAVE_OFFSET(amoeba_2_looks_like), O_AMOEBA_2},
+  {CAVE_OFFSET(amoeba_2_explosion_effect), O_SPACE},
+
+  // water
+  {CAVE_OFFSET(water_does_not_flow_down), FALSE},
+
+  // nut
+  {CAVE_OFFSET(nut_turns_to_when_crushed), O_NUT_EXPL_1},
+
+  // replicator
+  {CAVE_OFFSET(replicator_delay_frame), 4},
+  {CAVE_OFFSET(replicators_active), TRUE},
+
+  // conveyor belt
+  {CAVE_OFFSET(conveyor_belts_active), TRUE},
+  {CAVE_OFFSET(conveyor_belts_direction_changed), FALSE},
+
+  // slime
+  {CAVE_OFFSET(slime_predictable), TRUE},
+  {CAVE_OFFSET(level_slime_seed_c64), -1},
+  {CAVE_OFFSET(level_slime_permeability_c64), 0},
+  {CAVE_OFFSET(level_slime_permeability), 1000000},
+  {CAVE_OFFSET(slime_eats_1), O_DIAMOND},
+  {CAVE_OFFSET(slime_converts_1), O_DIAMOND_F},
+  {CAVE_OFFSET(slime_eats_2), O_STONE},
+  {CAVE_OFFSET(slime_converts_2), O_STONE_F},
+  {CAVE_OFFSET(slime_eats_3), O_NUT},
+  {CAVE_OFFSET(slime_converts_3), O_NUT_F},
+
+  // acid
+  {CAVE_OFFSET(acid_eats_this), O_DIRT},
+  {CAVE_OFFSET(acid_spread_ratio), 31250},
+  {CAVE_OFFSET(acid_turns_to), O_EXPLODE_3},
+
+  // biter
+  {CAVE_OFFSET(biter_delay_frame), 0},
+  {CAVE_OFFSET(biter_eat), O_DIAMOND},
+
+  // bladder
+  {CAVE_OFFSET(bladder_converts_by), O_VOODOO},
+
+  // SOUND
+  {CAVE_OFFSET(amoeba_sound), TRUE},
+  {CAVE_OFFSET(magic_wall_sound), TRUE},
+  {CAVE_OFFSET(slime_sound), TRUE},
+  {CAVE_OFFSET(lava_sound), TRUE},
+  {CAVE_OFFSET(replicator_sound), TRUE},
+  {CAVE_OFFSET(acid_spread_sound), TRUE},
+  {CAVE_OFFSET(biter_sound), TRUE},
+  {CAVE_OFFSET(bladder_sound), TRUE},
+  {CAVE_OFFSET(water_sound), TRUE},
+  {CAVE_OFFSET(stone_sound), TRUE},
+  {CAVE_OFFSET(nut_sound), TRUE},
+  {CAVE_OFFSET(diamond_sound), TRUE},
+  {CAVE_OFFSET(falling_wall_sound), TRUE},
+  {CAVE_OFFSET(expanding_wall_sound), TRUE},
+  {CAVE_OFFSET(nitro_sound), TRUE},
+  {CAVE_OFFSET(pneumatic_hammer_sound), TRUE},
+  {CAVE_OFFSET(bladder_spender_sound), TRUE},
+  {CAVE_OFFSET(bladder_convert_sound), TRUE},
+  {CAVE_OFFSET(gravity_change_sound), TRUE},
+  {CAVE_OFFSET(creature_direction_auto_change_sound), TRUE},
+
+  // creature effects
+  {CAVE_OFFSET(creatures_backwards), FALSE},
+  {CAVE_OFFSET(creatures_direction_auto_change_time), 0},
+  {CAVE_OFFSET(creatures_direction_auto_change_on_start), FALSE},
+
+  // cave effects
+  {CAVE_OFFSET(explosion_effect), O_SPACE},
+  {CAVE_OFFSET(diamond_birth_effect), O_DIAMOND},
+  {CAVE_OFFSET(bomb_explosion_effect), O_BRICK},
+  {CAVE_OFFSET(nitro_explosion_effect), O_SPACE},
+  {CAVE_OFFSET(firefly_explode_to), O_EXPLODE_1},
+  {CAVE_OFFSET(alt_firefly_explode_to), O_EXPLODE_1},
+  {CAVE_OFFSET(butterfly_explode_to), O_PRE_DIA_1},
+  {CAVE_OFFSET(alt_butterfly_explode_to), O_PRE_DIA_1},
+  {CAVE_OFFSET(stonefly_explode_to), O_PRE_STONE_1},
+  {CAVE_OFFSET(dragonfly_explode_to), O_EXPLODE_1},
+
+  {CAVE_OFFSET(stone_falling_effect), O_STONE_F},
+  {CAVE_OFFSET(stone_bouncing_effect), O_STONE},
+  {CAVE_OFFSET(diamond_falling_effect), O_DIAMOND_F},
+  {CAVE_OFFSET(diamond_bouncing_effect), O_DIAMOND},
+
+  // visual effects
+  {CAVE_OFFSET(expanding_wall_looks_like), O_BRICK},
+  {CAVE_OFFSET(dirt_looks_like), O_DIRT},
+
+  // gravity
+  {CAVE_OFFSET(gravity), GD_MV_DOWN},
+  {CAVE_OFFSET(gravity_switch_active), FALSE},
+  {CAVE_OFFSET(skeletons_needed_for_pot), 5},
+  {CAVE_OFFSET(gravity_change_time), 10},
+
+  // COMPATIBILITY
+  {CAVE_OFFSET(border_scan_first_and_last), TRUE},
+  {CAVE_OFFSET(lineshift), FALSE},
+  {CAVE_OFFSET(wraparound_objects), FALSE},
+  {CAVE_OFFSET(short_explosions), TRUE},
+  {CAVE_OFFSET(skeletons_worth_diamonds), 0},
+  {CAVE_OFFSET(gravity_affects_all), TRUE},
+
+  {-1},
+};
+
+// return new element, which appears after elem is hammered.
+// returns o_none, if elem is invalid for hammering.
+GdElement gd_element_get_hammered(GdElement elem)
+{
+  switch (elem)
+  {
+    // what is under the pneumatic hammer?
+    case O_WALLED_KEY_1:
+      return O_KEY_1;
+
+    case O_WALLED_KEY_2:
+      return O_KEY_2;
+
+    case O_WALLED_KEY_3:
+      return O_KEY_3;
+
+    case O_WALLED_DIAMOND:
+      return O_DIAMOND;
+
+    case O_BRICK:
+    case O_BRICK_SLOPED_UP_RIGHT:
+    case O_BRICK_SLOPED_UP_LEFT:
+    case O_BRICK_SLOPED_DOWN_RIGHT:
+    case O_BRICK_SLOPED_DOWN_LEFT:
+    case O_BRICK_NON_SLOPED:
+    case O_MAGIC_WALL:
+    case O_STEEL_EXPLODABLE:
+    case O_EXPANDING_WALL:
+    case O_V_EXPANDING_WALL:
+    case O_H_EXPANDING_WALL:
+    case O_FALLING_WALL:
+    case O_FALLING_WALL_F:
+      return O_SPACE;
+
+    default:
+      return O_NONE;
+  }
+}
+
+void gd_cave_db_init(void)
+{
+  int i;
+  HashTable *pointers;
+  boolean lowercase_names = TRUE;
+
+  // TRANSLATORS: some languages (for example, german) do not have lowercase nouns.
+  // When gdash generates the list of lowercase element names, this has to be
+  // taken into account. Therefore we have a string, which must be changed
+  // by the translator to select the behavior.
+  // For example, the name of the element is "Brick wall", as in a button, it has to be
+  // written with an uppercase initial. But if "Line of brick wall", the B is changed to b.
+  // However, this is not allowed in some languages, for example, German.
+  // So one writes "Ziegelmauer", and "Linie aus Ziegelmauer", the Z is not changed to z.
+  // Set the translated string to "lowercase-element-names-yes", if your language
+  // allows writing nouns with lowercase initials. Set it to "lowercase-element-names-no",
+  // if not: for example, german. Do not translate the string, but set the behavior!
+
+  if (strEqual(_("lowercase-element-names-yes"), "lowercase-element-names-no"))
+    lowercase_names = FALSE;
+
+  // check element database for faults.
+  for (i = 0; gd_elements[i].element != -1; i++)
+  {
+    if (gd_elements[i].element != i)
+      Error("element: i:0x%x != 0x%x", i, gd_elements[i].element);
+
+    // if it has a name, create a lowercase name (of the translated one).
+    // will be used by the editor
+    if (gd_elements[i].name)
+    {
+      if (lowercase_names)
+       // the function allocates a new string, but it is needed as long as the app is running
+       gd_elements[i].lowercase_name = getStringToLower(gettext(gd_elements[i].name));
+      else
+       // only translate, no lowercase.
+       gd_elements[i].lowercase_name = gettext(gd_elements[i].name);
+    }
+
+    // we do not like generated pixbufs for games. only those that are in the png.
+    if (ABS(gd_elements[i].image_game) > GD_NUM_OF_CELLS_X * GD_NUM_OF_CELLS_Y)
+      Error("game pixbuf for element %x (%s) bigger than png size", i, gd_elements[i].name);
+
+    if (gd_elements[i].image < 0)
+      Error("editor pixbuf for element %x (%s) should not be animated", i, gd_elements[i].name);
+
+    if (gd_elements[i].properties & P_CAN_BE_HAMMERED && gd_element_get_hammered((GdElement) i) == O_NONE)
+      Error("element %x (%s) can be hammered, but get_hammered_element does not define another one", i, gd_elements[i].name);
+  }
+
+  /*
+    NOT REALLY NEEDED ANYMORE, as the enum takes care of it.
+    maybe to show that there is an unnecessary one.
+  */
+  /*
+    g_print("Free pixbuf indexes: ");
+    for (i = GD_NUM_OF_CELLS_X*GD_NUM_OF_CELLS_Y; i<GD_NUM_OF_CELLS; i++)
+    {
+    if (!cell_used[i])
+    g_print("%d ", i);
+    }
+    g_print("\n");
+  */
+
+  // uncomment this, to show free element->character characters.
+  /*
+    gd_create_char_to_element_table();
+    g_print("Free characters: ");
+    for (i = 32; i < 128; i++)
+    if (gd_char_to_element[i] == O_UNKNOWN)
+    g_print("%c", i);
+    g_print("\n");
+  */
+
+  // check the cave property database for faults.
+  pointers = create_hashtable(get_hash_from_integer, hash_key_integers_are_equal, NULL, NULL);
+
+  for (i = 0; gd_cave_properties[i].identifier != NULL; i++)
+  {
+    GdType type = gd_cave_properties[i].type;
+
+    switch (type)
+    {
+      case GD_LABEL:
+      case GD_TAB:
+       // some lines are used for the user interface. these should not have an identifier.
+       if (strcmp(gd_cave_properties[i].identifier, "") != 0)
+       {
+         Error ("ui lines in cave properties should not have identifiers: %s",
+                gd_cave_properties[i].identifier);
+       }
+       break;
+
+      case GD_TYPE_STRING:
+       // check if any of the properties are designated as string arrays.
+       // they are not supported in file read/write and operations,
+       // also they do not even make any sense!
+       if (gd_cave_properties[i].count != 1)
+       {
+         Error ("string arrays have no sense in cave properties: %s",
+                gd_cave_properties[i].identifier);
+       }
+       break;
+
+      case GD_TYPE_LONGSTRING:
+       if (gd_cave_properties[i].count != 1)
+       {
+         Error ("longstring arrays have no sense cave properties: %s",
+                gd_cave_properties[i].identifier);
+       }
+       break;
+
+      case GD_TYPE_EFFECT:
+       // the same applies for effects.
+       if (gd_cave_properties[i].count != 1)
+       {
+         Error ("effect arrays not supported in cave properties: %s",
+                gd_cave_properties[i].identifier);
+       }
+       break;
+
+      case GD_TYPE_COLOR:
+       // the same applies for effects.
+       if (gd_cave_properties[i].count != 1)
+       {
+         Error ("color arrays not supported in cave properties: %s",
+                gd_cave_properties[i].identifier);
+       }
+       break;
+
+      default:
+       break;
+    }
+
+    if (type != GD_LABEL && (gd_cave_properties[i].flags & GD_SHOW_LEVEL_LABEL))
+    {
+      Error ("show_level_label only for labels: line %d", i);
+    }
+
+    if (type != GD_LABEL && type != GD_TAB)
+    {
+      const char *another_prop;
+
+      // other types
+      // check if its pointer is not the same as another one's
+      // +1 is added so it is never zero
+      if (!(gd_cave_properties[i].flags & GD_DONT_SAVE) && strcmp(gd_cave_properties[i].identifier, "") == 0)
+      {
+       Error ("property should have a bdcff identifier: line %d, name %s",
+              i, gd_cave_properties[i].name);
+      }
+
+      another_prop = hashtable_search(pointers, INT_TO_PTR(gd_cave_properties[i].offset + 1));
+
+      if (another_prop != NULL)
+      {
+       Error("property %s has the same pointer as property %s",
+             gd_cave_properties[i].identifier, another_prop);
+      }
+      else
+      {
+       // value is the identifier, so we can report the OLD one if the check fails
+       hashtable_insert(pointers, INT_TO_PTR(gd_cave_properties[i].offset + 1),
+                        gd_cave_properties[i].identifier);
+      }
+    }
+  }
+
+  hashtable_destroy(pointers);
+}
diff --git a/src/game_bd/bd_cavedb.h b/src/game_bd/bd_cavedb.h
new file mode 100644 (file)
index 0000000..747bfdd
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVEDB_H
+#define BD_CAVEDB_H
+
+#include "bd_cave.h"
+
+
+extern GdElements gd_elements[];
+
+extern const GdStructDescriptor gd_cave_properties[];
+extern const GdStructDescriptor gd_replay_properties[];
+
+extern GdPropertyDefault gd_cave_defaults_gdash[];
+
+// do some checks on the cave db
+void gd_cave_db_init(void);
+GdElement gd_element_get_hammered(GdElement elem);
+
+#endif // BD_CAVEDB_H
diff --git a/src/game_bd/bd_caveengine.c b/src/game_bd/bd_caveengine.c
new file mode 100644 (file)
index 0000000..ee1b4ee
--- /dev/null
@@ -0,0 +1,3919 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// IMPORTANT NOTES
+
+/*
+ * LAVA.
+ *
+ * Lava absorbs everything going into it. Everything.
+ * But it does not "pull" elements; only the things disappear which
+ * _do_ go directly into it. So if the player steps into the lava,
+ * he will die. If a dragonfly flies over it, it will not.
+ *
+ * This behavior is implemented in the is_space_dir and the store
+ * functions. is_space_dir returns true for the lava, too. The store
+ * function ignores any store requests into the lava.
+ * The player_get function will also behave for lava as it does for space.
+ */
+
+#include "main_bd.h"
+
+
+// for gravity
+static const GdDirection ccw_eighth[] =
+{
+  GD_MV_STILL,
+  GD_MV_UP_LEFT,
+  GD_MV_UP,
+  GD_MV_UP_RIGHT,
+  GD_MV_RIGHT,
+  GD_MV_DOWN_RIGHT,
+  GD_MV_DOWN,
+  GD_MV_DOWN_LEFT
+};
+
+static const GdDirection ccw_fourth[] =
+{
+  GD_MV_STILL,
+  GD_MV_LEFT,
+  GD_MV_UP_LEFT,
+  GD_MV_UP,
+  GD_MV_UP_RIGHT,
+  GD_MV_RIGHT,
+  GD_MV_DOWN_RIGHT,
+  GD_MV_DOWN,
+  GD_MV_DOWN_LEFT,
+  GD_MV_LEFT
+};
+
+static const GdDirection cw_eighth[] =
+{
+  GD_MV_STILL,
+  GD_MV_UP_RIGHT,
+  GD_MV_RIGHT,
+  GD_MV_DOWN_RIGHT,
+  GD_MV_DOWN,
+  GD_MV_DOWN_LEFT,
+  GD_MV_LEFT,
+  GD_MV_UP_LEFT,
+  GD_MV_UP
+};
+
+static const GdDirection cw_fourth[] =
+{
+  GD_MV_STILL,
+  GD_MV_RIGHT,
+  GD_MV_DOWN_RIGHT,
+  GD_MV_DOWN,
+  GD_MV_DOWN_LEFT,
+  GD_MV_LEFT,
+  GD_MV_UP_LEFT,
+  GD_MV_UP,
+  GD_MV_UP_RIGHT
+};
+
+static const GdDirection opposite[] =
+{
+  GD_MV_STILL,
+  GD_MV_DOWN,
+  GD_MV_DOWN_LEFT,
+  GD_MV_LEFT,
+  GD_MV_UP_LEFT,
+  GD_MV_UP,
+  GD_MV_UP_RIGHT,
+  GD_MV_RIGHT,
+  GD_MV_DOWN_RIGHT
+};
+
+// sets timeout sound.
+void gd_cave_set_seconds_sound(GdCave *cave)
+{
+  // when not counting bonus time, timeout sounds will be played by main game engine;
+  // also skip timeout sounds when not using native sound engine
+  if (game_bd.game == NULL || game_bd.game->state_counter != GAME_INT_CHECK_BONUS_TIME ||
+      !game.use_native_bd_sound_engine)
+    return;
+
+  // this is an integer division, so 0 seconds can be 0.5 seconds...
+  // also, when this reaches 8, the player still has 8.9999 seconds.
+  // so the sound is played at almost t = 9s.
+  switch (cave->time / cave->timing_factor)
+  {
+    case 9: gd_sound_play(cave, GD_S_TIMEOUT_10, O_NONE, -1, -1); break;
+    case 8: gd_sound_play(cave, GD_S_TIMEOUT_9,  O_NONE, -1, -1); break;
+    case 7: gd_sound_play(cave, GD_S_TIMEOUT_8,  O_NONE, -1, -1); break;
+    case 6: gd_sound_play(cave, GD_S_TIMEOUT_7,  O_NONE, -1, -1); break;
+    case 5: gd_sound_play(cave, GD_S_TIMEOUT_6,  O_NONE, -1, -1); break;
+    case 4: gd_sound_play(cave, GD_S_TIMEOUT_5,  O_NONE, -1, -1); break;
+    case 3: gd_sound_play(cave, GD_S_TIMEOUT_4,  O_NONE, -1, -1); break;
+    case 2: gd_sound_play(cave, GD_S_TIMEOUT_3,  O_NONE, -1, -1); break;
+    case 1: gd_sound_play(cave, GD_S_TIMEOUT_2,  O_NONE, -1, -1); break;
+    case 0: gd_sound_play(cave, GD_S_TIMEOUT_1,  O_NONE, -1, -1); break;
+  }
+}
+
+// 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;
+}
+
+// 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())
+    return;
+
+  // stone and diamond fall sounds.
+  switch (element)
+  {
+    case O_NUT:
+      gd_sound_play(cave, GD_S_NUT_FALLING, element, x, y);
+      break;
+
+    case O_NUT_F:
+      gd_sound_play(cave, GD_S_NUT_IMPACT, element, x, y);
+      break;
+
+    case O_STONE:
+      gd_sound_play(cave, GD_S_STONE_FALLING, element, x, y);
+      break;
+
+    case O_STONE_F:
+      gd_sound_play(cave, GD_S_STONE_IMPACT, element, x, y);
+      break;
+
+    case O_FLYING_STONE:
+      gd_sound_play(cave, GD_S_FLYING_STONE_FALLING, element, x, y);
+      break;
+
+    case O_FLYING_STONE_F:
+      gd_sound_play(cave, GD_S_FLYING_STONE_IMPACT, element, x, y);
+      break;
+
+    case O_MEGA_STONE:
+      gd_sound_play(cave, GD_S_MEGA_STONE_FALLING, element, x, y);
+      break;
+
+    case O_MEGA_STONE_F:
+      gd_sound_play(cave, GD_S_MEGA_STONE_IMPACT, element, x, y);
+      break;
+
+    case O_NITRO_PACK:
+      gd_sound_play(cave, GD_S_NITRO_PACK_FALLING, element, x, y);
+      break;
+
+    case O_NITRO_PACK_F:
+      gd_sound_play(cave, GD_S_NITRO_PACK_IMPACT, element, x, y);
+      break;
+
+    case O_FALLING_WALL:
+      gd_sound_play(cave, GD_S_FALLING_WALL_FALLING, element, x, y);
+      break;
+
+    case O_FALLING_WALL_F:
+      gd_sound_play(cave, GD_S_FALLING_WALL_IMPACT, element, x, y);
+      break;
+
+    case O_H_EXPANDING_WALL:
+    case O_V_EXPANDING_WALL:
+    case O_EXPANDING_WALL:
+    case O_H_EXPANDING_STEEL_WALL:
+    case O_V_EXPANDING_STEEL_WALL:
+    case O_EXPANDING_STEEL_WALL:
+      gd_sound_play(cave, GD_S_EXPANDING_WALL, element, x, y);
+      break;
+
+    case O_DIAMOND:
+      gd_sound_play(cave, GD_S_DIAMOND_FALLING_RANDOM, element, x, y);
+      break;
+
+    case O_DIAMOND_F:
+      gd_sound_play(cave, GD_S_DIAMOND_IMPACT_RANDOM, element, x, y);
+      break;
+
+    case O_FLYING_DIAMOND:
+      gd_sound_play(cave, GD_S_FLYING_DIAMOND_FALLING_RANDOM, element, x, y);
+      break;
+
+    case O_FLYING_DIAMOND_F:
+      gd_sound_play(cave, GD_S_FLYING_DIAMOND_IMPACT_RANDOM, element, x, y);
+      break;
+
+    case O_BLADDER_SPENDER:
+      gd_sound_play(cave, GD_S_BLADDER_SPENDER, element, x, y);
+      break;
+
+    case O_PRE_CLOCK_1:
+      gd_sound_play(cave, GD_S_BLADDER_CONVERTING, element, x, y);
+      break;
+
+    case O_SLIME:
+      gd_sound_play(cave, GD_S_SLIME, element, x, y);
+      break;
+
+    case O_LAVA:
+      gd_sound_play(cave, GD_S_LAVA, element, x, y);
+      break;
+
+    case O_ACID:
+      gd_sound_play(cave, GD_S_ACID_SPREADING, element, x, y);
+      break;
+
+    case O_BLADDER:
+      gd_sound_play(cave, GD_S_BLADDER_MOVING, element, x, y);
+      break;
+
+    case O_BITER_1:
+    case O_BITER_2:
+    case O_BITER_3:
+    case O_BITER_4:
+      gd_sound_play(cave, GD_S_BITER_EATING, element, x, y);
+      break;
+
+    case O_DIRT_BALL:
+      gd_sound_play(cave, GD_S_DIRT_BALL_FALLING, element, x, y);
+      break;
+
+    case O_DIRT_BALL_F:
+      gd_sound_play(cave, GD_S_DIRT_BALL_IMPACT, element, x, y);
+      break;
+
+    case O_DIRT_LOOSE:
+      gd_sound_play(cave, GD_S_DIRT_LOOSE_FALLING, element, x, y);
+      break;
+
+    case O_DIRT_LOOSE_F:
+      gd_sound_play(cave, GD_S_DIRT_LOOSE_IMPACT, element, x, y);
+      break;
+
+    default:
+      // do nothing.
+      break;
+  }
+}
+
+// play sound of given element being pushed.
+static void play_sound_of_element_pushing(GdCave *cave, GdElement element, int x, int y)
+{
+  switch (element)
+  {
+    case O_NUT:
+      gd_sound_play(cave, GD_S_NUT_PUSHING, element, x, y);
+      break;
+
+    case O_STONE:
+      gd_sound_play(cave, GD_S_STONE_PUSHING, element, x, y);
+      break;
+
+    case O_FLYING_STONE:
+      gd_sound_play(cave, GD_S_FLYING_STONE_PUSHING, element, x, y);
+      break;
+
+    case O_MEGA_STONE:
+      gd_sound_play(cave, GD_S_MEGA_STONE_PUSHING, element, x, y);
+      break;
+
+    case O_WAITING_STONE:
+      gd_sound_play(cave, GD_S_WAITING_STONE_PUSHING, element, x, y);
+      break;
+
+    case O_CHASING_STONE:
+      gd_sound_play(cave, GD_S_CHASING_STONE_PUSHING, element, x, y);
+      break;
+
+    case O_NITRO_PACK:
+      gd_sound_play(cave, GD_S_NITRO_PACK_PUSHING, element, x, y);
+      break;
+
+    case O_BLADDER:
+      gd_sound_play(cave, GD_S_BLADDER_PUSHING, element, x, y);
+      break;
+
+    default:
+      // do nothing.
+      break;
+  }
+}
+
+static inline int getx(const GdCave *cave, const int x, const int y)
+{
+  return cave->getx(cave, x, y);
+}
+
+static inline int gety(const GdCave *cave, const int x, const int y)
+{
+  return cave->gety(cave, x, y);
+}
+
+// perfect (non-lineshifting) GET x/y functions; returns range corrected x/y position
+static inline int getx_perfect(const GdCave *cave, const int x, const int y)
+{
+  return (x + cave->w) % cave->w;
+}
+
+static inline int gety_perfect(const GdCave *cave, const int x, const int y)
+{
+  return (y + cave->h) % cave->h;
+}
+
+// line shifting GET x/y function; returns range corrected x/y position
+static inline int getx_shift(const GdCave *cave, int x, int y)
+{
+  return (x + cave->w) % cave->w;
+}
+
+static inline int gety_shift(const GdCave *cave, int x, int y)
+{
+  return ((x < 0 ? y - 1 : x >= cave->w ? y + 1 : y) + cave->h) % cave->h;
+}
+
+static inline GdElement *getp(const GdCave *cave, const int x, const int y)
+{
+  return cave->getp(cave, x, y);
+}
+
+/*
+  perfect (non-lineshifting) GET function.
+  returns a pointer to a selected cave element by its coordinates.
+*/
+static inline GdElement *getp_perfect(const GdCave *cave, const int x, const int y)
+{
+  // (x + n) mod n: this works also for x >= n and -n + 1 < x < 0
+  return &(cave->map[(y + cave->h) % cave->h][(x + cave->w) % cave->w]);
+}
+
+/*
+  line shifting GET function; returns a pointer to the selected cave element.
+  this is used to emulate the line-shifting behaviour of original games, so that
+  the player entering one side will appear one row above or below on the other.
+*/
+static inline GdElement *getp_shift(const GdCave *cave, int x, int y)
+{
+  if (x >= cave->w)
+  {
+    y++;
+    x -= cave->w;
+  }
+  else if (x < 0)
+  {
+    y--;
+    x += cave->w;
+  }
+
+  y = (y + cave->h) % cave->h;
+
+  return &(cave->map[y][x]);
+}
+
+static inline GdElement get(const GdCave *cave, const int x, const int y)
+{
+  return *getp(cave, x, y);
+}
+
+// returns an element which is somewhere near x,y
+static inline GdElement get_dir(const GdCave *cave, const int x, const int y,
+                               const GdDirection dir)
+{
+  return get(cave, x + gd_dx[dir], y + gd_dy[dir]);
+}
+
+static inline boolean explodes_by_hit_dir(const GdCave *cave, const int x,
+                                         const int y, GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_EXPLODES_BY_HIT) != 0;
+}
+
+// returns true if the element is not explodable, for example the steel wall
+static inline boolean non_explodable(const GdCave *cave, const int x, const int y)
+{
+  return (gd_elements[get(cave, x,y) & O_MASK].properties & P_NON_EXPLODABLE) != 0;
+}
+
+// returns true if the element can be eaten by the amoeba, eg. space and dirt.
+static inline boolean amoeba_eats_dir(const GdCave *cave, const int x, const int y,
+                                     const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_AMOEBA_CONSUMES) != 0;
+}
+
+// returns true if the element is sloped, so stones and diamonds roll down on it.
+// for example a stone or brick wall
+static inline boolean sloped_dir(const GdCave *cave, const int x, const int y,
+                                const GdDirection dir, const GdDirection slop)
+{
+  switch (slop)
+  {
+    case GD_MV_LEFT:
+      return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_LEFT) != 0;
+
+    case GD_MV_RIGHT:
+      return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_RIGHT) != 0;
+
+    case GD_MV_UP:
+      return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_UP) != 0;
+
+    case GD_MV_DOWN:
+      return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_SLOPED_DOWN) != 0;
+
+    default:
+      break;
+  }
+
+  return FALSE;
+}
+
+// returns true if the element is sloped for bladder movement
+// (brick = yes, diamond = no, for example)
+static inline boolean sloped_for_bladder_dir (const GdCave *cave, const int x, const int y,
+                                             const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_BLADDER_SLOPED) != 0;
+}
+
+static inline boolean blows_up_flies_dir(const GdCave *cave, const int x, const int y,
+                                        const GdDirection dir)
+{
+    return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_BLOWS_UP_FLIES) != 0;
+}
+
+// returns true if the element is a counter-clockwise creature
+static inline boolean rotates_ccw (const GdCave *cave, const int x, const int y)
+{
+  return (gd_elements[get(cave, x, y) & O_MASK].properties & P_CCW) != 0;
+}
+
+// returns true if the element is a player
+boolean is_player(const GdCave *cave, const int x, const int y)
+{
+  return (gd_elements[get(cave, x, y) & O_MASK].properties & P_PLAYER) != 0;
+}
+
+// returns true if the element is a player
+static inline boolean is_player_dir(const GdCave *cave, const int x, const int y,
+                                   const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PLAYER) != 0;
+}
+
+static inline boolean can_be_hammered_dir(const GdCave *cave, const int x, const int y,
+                                         const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_CAN_BE_HAMMERED) != 0;
+}
+
+// returns true if the element can be pushed
+boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y,
+                         const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_PUSHABLE) != 0;
+}
+
+// returns true if the element is explodable and explodes to space, for example the player
+static inline boolean is_first_stage_of_explosion(const GdCave *cave, const int x, const int y)
+{
+  return (gd_elements[get(cave, x, y) & O_MASK].properties & P_EXPLOSION_FIRST_STAGE) != 0;
+}
+
+// returns true if the element is moved by the conveyor belt
+static inline boolean moved_by_conveyor_top_dir(const GdCave *cave, const int x, const int y,
+                                               const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_MOVED_BY_CONVEYOR_TOP) != 0;
+}
+
+// returns true if the element is moved by the conveyor belt
+static inline boolean moved_by_conveyor_bottom_dir(const GdCave *cave, const int x, const int y,
+                                                  const GdDirection dir)
+{
+  return (gd_elements[get_dir(cave, x, y, dir) & O_MASK].properties & P_MOVED_BY_CONVEYOR_BOTTOM) != 0;
+}
+
+static inline boolean is_scanned_dir(const GdCave *cave, const int x, const int y,
+                                    const GdDirection dir)
+{
+  return (get_dir(cave, x, y, dir) & SCANNED) != 0;
+}
+
+// returns true if neighbouring element is "e"
+// treats dirt specially
+// treats lava specially
+static inline boolean is_element_dir(const GdCave *cave, const int x, const int y,
+                                    const GdDirection dir, GdElement e)
+{
+  GdElement examined = get_dir(cave, x, y, dir);
+
+  // if it is a dirt-like, change to dirt, so equality will evaluate to true
+  if (gd_elements[examined & O_MASK].properties & P_DIRT)
+    examined = O_DIRT;
+
+  if (gd_elements[e & O_MASK].properties & P_DIRT)
+    e = O_DIRT;
+
+  // if the element on the map is a lava, it should be like space
+  if (examined == O_LAVA)
+    examined = O_SPACE;
+
+  return (e == examined);
+}
+
+// returns true if neighbouring element is space
+static inline boolean is_space_dir(const GdCave *cave, const int x, const int y,
+                                  const GdDirection dir)
+{
+  GdElement e = get_dir(cave, x, y, dir) & O_MASK;
+
+  return (e == O_SPACE || e == O_LAVA);
+}
+
+static inline void store_dir_buffer(GdCave *cave, const int x, const int y, const GdDirection dir)
+{
+  // raw values without range correction
+  int raw_x = x + gd_dx[dir];
+  int raw_y = y + gd_dy[dir];
+
+  // final values with range correction
+  int new_x = getx(cave, raw_x, raw_y);
+  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;
+}
+
+// store an element at the given position
+static inline void store(GdCave *cave, const int x, const int y, const GdElement element)
+{
+  GdElement *e = getp(cave, x, y);
+
+  if (*e == O_LAVA)
+  {
+    play_sound_of_element(cave, O_LAVA, x, y);
+
+    return;
+  }
+
+  *e = element;
+}
+
+// store an element with SCANNED flag turned on
+static inline void store_sc(GdCave *cave, const int x, const int y, const GdElement element)
+{
+  store(cave, x, y, element | SCANNED);
+}
+
+// store an element to a neighbouring cell
+static inline void store_dir(GdCave *cave, const int x, const int y,
+                            const GdDirection dir, const GdElement element)
+{
+  store_dir_buffer(cave, x, y, dir);
+  store(cave, x + gd_dx[dir], y + gd_dy[dir], element | SCANNED);
+}
+
+// store an element to a neighbouring cell
+static inline void store_dir_no_scanned(GdCave *cave, const int x, const int y,
+                                       const GdDirection dir, const GdElement element)
+{
+  store_dir_buffer(cave, x, y, dir);
+  store(cave, x + gd_dx[dir], y + gd_dy[dir], element);
+}
+
+// move element to direction; then place space at x, y
+static inline void move(GdCave *cave, const int x, const int y,
+                       const GdDirection dir, const GdElement e)
+{
+  store_dir(cave, x, y, dir, e);
+  store(cave, x, y, O_SPACE);
+}
+
+// increment a cave element; can be used for elements which are one after
+// the other, for example bladder1, bladder2, bladder3...
+static inline void next(GdCave *cave, const int x, const int y)
+{
+  (*getp(cave, x, y))++;
+}
+
+static void cell_explode(GdCave *cave, int x, int y, GdElement explode_to)
+{
+  if (non_explodable (cave, x, y))
+    return;
+
+  if (cave->voodoo_any_hurt_kills_player && get(cave, x, y) == O_VOODOO)
+    cave->voodoo_touched = TRUE;
+
+  if (get(cave, x, y) == O_VOODOO && !cave->voodoo_disappear_in_explosion)
+    // voodoo turns into a time penalty
+    store_sc(cave, x, y, O_TIME_PENALTY);
+  else if (get(cave, x, y) == O_NITRO_PACK ||
+          get(cave, x, y) == O_NITRO_PACK_F)
+    // nitro pack inside an explosion - it is now triggered
+    store_sc(cave, x, y, O_NITRO_PACK_EXPLODE);
+  else
+    // for everything else
+    store_sc(cave, x, y, explode_to);
+}
+
+// a creature explodes to a 3x3 something.
+static void creature_explode(GdCave *cave, int x, int y, GdElement explode_to)
+{
+  int xx, yy;
+
+  // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
+  cave->ckdelay += 1200;
+  gd_sound_play(cave, GD_S_EXPLODING, get(cave, x, y), x, y);
+
+  for (yy = y - 1; yy <= y + 1; yy++)
+    for (xx = x - 1; xx <= x + 1; xx++)
+      cell_explode(cave, xx, yy, explode_to);
+}
+
+static void nitro_explode(GdCave *cave, int x, int y)
+{
+  int xx, yy;
+
+  // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
+  cave->ckdelay += 1200;
+  gd_sound_play(cave, GD_S_NITRO_PACK_EXPLODING, get(cave, x, y), x, y);
+
+  for (yy = y - 1; yy <= y + 1; yy++)
+    for (xx = x - 1; xx <= x + 1; xx++)
+      cell_explode(cave, xx, yy, O_NITRO_EXPL_1);
+
+  // the current cell is explicitly changed into a nitro expl,
+  // as cell_explode changes it to a triggered nitro pack
+  store_sc(cave, x, y, O_NITRO_EXPL_1);
+}
+
+// a voodoo explodes, leaving a 3x3 steel and a time penalty behind.
+static void voodoo_explode(GdCave *cave, int x, int y)
+{
+  int xx, yy;
+
+  // the processing of an explosion took pretty much time: processing 3x3 = 9 elements
+  cave->ckdelay += 1000;
+
+  gd_sound_play(cave, GD_S_VOODOO_EXPLODING, get(cave, x, y), x, y);
+  if (cave->voodoo_any_hurt_kills_player)
+    cave->voodoo_touched = TRUE;
+
+  // voodoo explodes to 3x3 steel
+  for (yy = y - 1; yy <= y + 1; yy++)
+    for (xx = x - 1; xx <= x + 1; xx++)
+      store_sc(cave, xx, yy, O_PRE_STEEL_1);
+
+  // middle is a time penalty (which will be turned into a gravestone)
+  store_sc(cave, x, y, O_TIME_PENALTY);
+}
+
+/*
+  a bomb does not explode the voodoo, neither does the ghost.
+  this function check this, and stores the new element or not.
+  destroying the voodoo is also controlled by the
+  voodoo_disappear_in_explosion flag.
+*/
+static void explode_try_skip_voodoo(GdCave *cave, const int x, const int y, const GdElement expl)
+{
+  if (non_explodable (cave, x, y))
+    return;
+
+  // bomb does not explode voodoo
+  if (!cave->voodoo_disappear_in_explosion && get(cave, x, y) == O_VOODOO)
+    return;
+
+  if (cave->voodoo_any_hurt_kills_player && get(cave, x, y) == O_VOODOO)
+    cave->voodoo_touched = TRUE;
+
+  store_sc (cave, x, y, expl);
+}
+
+// X shaped ghost explosion; does not touch voodoo!
+static void ghost_explode(GdCave *cave, const int x, const int y)
+{
+  gd_sound_play(cave, GD_S_GHOST_EXPLODING, get(cave, x, y), x, y);
+
+  // the processing of an explosion took pretty much time: processing 5 elements
+  cave->ckdelay += 650;
+
+  explode_try_skip_voodoo(cave, x,     y,     O_GHOST_EXPL_1);
+  explode_try_skip_voodoo(cave, x - 1, y - 1, O_GHOST_EXPL_1);
+  explode_try_skip_voodoo(cave, x + 1, y + 1, O_GHOST_EXPL_1);
+  explode_try_skip_voodoo(cave, x - 1, y + 1, O_GHOST_EXPL_1);
+  explode_try_skip_voodoo(cave, x + 1, y - 1, O_GHOST_EXPL_1);
+}
+
+// +shaped bomb explosion; does not touch voodoo!
+static void bomb_explode(GdCave *cave, const int x, const int y)
+{
+  gd_sound_play(cave, GD_S_BOMB_EXPLODING, get(cave, x, y), x, y);
+
+  // the processing of an explosion took pretty much time: processing 5 elements
+  cave->ckdelay += 650;
+
+  explode_try_skip_voodoo(cave, x,     y,     O_BOMB_EXPL_1);
+  explode_try_skip_voodoo(cave, x - 1, y,     O_BOMB_EXPL_1);
+  explode_try_skip_voodoo(cave, x + 1, y,     O_BOMB_EXPL_1);
+  explode_try_skip_voodoo(cave, x,     y + 1, O_BOMB_EXPL_1);
+  explode_try_skip_voodoo(cave, x,     y - 1, O_BOMB_EXPL_1);
+}
+
+/*
+  explode an element with the appropriate type of exlposion.
+ */
+static void explode(GdCave *cave, int x, int y)
+{
+  GdElement e = get(cave, x, y) & O_MASK;
+
+  switch (e)
+  {
+    case O_GHOST:
+      ghost_explode(cave, x, y);
+      break;
+
+    case O_BOMB_TICK_7:
+      bomb_explode(cave, x, y);
+      break;
+
+    case O_VOODOO:
+      voodoo_explode(cave, x, y);
+      break;
+
+    case O_NITRO_PACK:
+    case O_NITRO_PACK_F:
+    case O_NITRO_PACK_EXPLODE:
+      nitro_explode(cave, x, y);
+      break;
+
+    case O_AMOEBA_2:
+      creature_explode(cave, x, y, O_AMOEBA_2_EXPL_1);
+      break;
+
+    case O_FALLING_WALL_F:
+      creature_explode(cave, x, y, O_EXPLODE_1);
+      break;
+
+    case O_ROCKET_1:
+    case O_ROCKET_2:
+    case O_ROCKET_3:
+    case O_ROCKET_4:
+      creature_explode(cave, x, y, O_EXPLODE_1);
+      break;
+
+    case O_BUTTER_1:
+    case O_BUTTER_2:
+    case O_BUTTER_3:
+    case O_BUTTER_4:
+      creature_explode(cave, x, y, cave->butterfly_explode_to);
+      break;
+
+    case O_ALT_BUTTER_1:
+    case O_ALT_BUTTER_2:
+    case O_ALT_BUTTER_3:
+    case O_ALT_BUTTER_4:
+      creature_explode(cave, x, y, cave->alt_butterfly_explode_to);
+      break;
+
+    case O_FIREFLY_1:
+    case O_FIREFLY_2:
+    case O_FIREFLY_3:
+    case O_FIREFLY_4:
+      creature_explode(cave, x, y, cave->firefly_explode_to);
+      break;
+
+    case O_ALT_FIREFLY_1:
+    case O_ALT_FIREFLY_2:
+    case O_ALT_FIREFLY_3:
+    case O_ALT_FIREFLY_4:
+      creature_explode(cave, x, y, cave->alt_firefly_explode_to);
+      break;
+
+    case O_PLAYER:
+    case O_PLAYER_BOMB:
+    case O_PLAYER_GLUED:
+    case O_PLAYER_STIRRING:
+    case O_PLAYER_ROCKET_LAUNCHER:
+    case O_PLAYER_PNEUMATIC_LEFT:
+    case O_PLAYER_PNEUMATIC_RIGHT:
+      creature_explode(cave, x, y, O_EXPLODE_1);
+      break;
+
+    case O_STONEFLY_1:
+    case O_STONEFLY_2:
+    case O_STONEFLY_3:
+    case O_STONEFLY_4:
+      creature_explode(cave, x, y, cave->stonefly_explode_to);
+      break;
+
+    case O_DRAGONFLY_1:
+    case O_DRAGONFLY_2:
+    case O_DRAGONFLY_3:
+    case O_DRAGONFLY_4:
+      creature_explode(cave, x, y, cave->dragonfly_explode_to);
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void inline explode_dir(GdCave *cave, const int x, const int y, GdDirection dir)
+{
+  explode(cave, x + gd_dx[dir], y + gd_dy[dir]);
+}
+
+/*
+  player eats specified object.
+  returns O_SPACE if he eats it (diamond, dirt, space, outbox)
+  returns other element if something other appears there and he can't move.
+  cave pointer is needed to know the diamond values.
+*/
+static GdElement player_get_element(GdCave* cave, const GdElement object, int x, int y)
+{
+  int i;
+
+  switch (object)
+  {
+    case O_DIAMOND_KEY:
+      cave->diamond_key_collected = TRUE;
+      gd_sound_play(cave, GD_S_DIAMOND_KEY_COLLECTING, object, x, y);
+      return O_SPACE;
+
+    // KEYS AND DOORS
+    case O_KEY_1:
+      gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
+      cave->key1++;
+      return O_SPACE;
+
+    case O_KEY_2:
+      gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
+      cave->key2++;
+      return O_SPACE;
+
+    case O_KEY_3:
+      gd_sound_play(cave, GD_S_KEY_COLLECTING, object, x, y);
+      cave->key3++;
+      return O_SPACE;
+
+    case O_DOOR_1:
+      if (cave->key1 == 0)
+       return object;
+      gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
+      cave->key1--;
+      return O_SPACE;
+
+    case O_DOOR_2:
+      if (cave->key2 == 0)
+       return object;
+      gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
+      cave->key2--;
+      return O_SPACE;
+
+    case O_DOOR_3:
+      if (cave->key3 == 0)
+       return object;
+      gd_sound_play(cave, GD_S_DOOR_OPENING, object, x, y);
+      cave->key3--;
+      return O_SPACE;
+
+    // SWITCHES
+    case O_CREATURE_SWITCH:        // creatures change direction.
+      gd_sound_play(cave, GD_S_SWITCH_CREATURES, object, x, y);
+      cave->creatures_backwards = !cave->creatures_backwards;
+      return object;
+
+    case O_EXPANDING_WALL_SWITCH:        // expanding wall change direction.
+      gd_sound_play(cave, GD_S_SWITCH_EXPANDING, object, x, y);
+      cave->expanding_wall_changed = !cave->expanding_wall_changed;
+      return object;
+
+    case O_BITER_SWITCH:        // biter change delay
+      gd_sound_play(cave, GD_S_SWITCH_BITER, object, x, y);
+      cave->biter_delay_frame++;
+      if (cave->biter_delay_frame == 4)
+       cave->biter_delay_frame = 0;
+      return object;
+
+    case O_REPLICATOR_SWITCH:    // replicator on/off switch
+      gd_sound_play(cave, GD_S_SWITCH_REPLICATOR, object, x, y);
+      cave->replicators_active = !cave->replicators_active;
+      return object;
+
+    case O_CONVEYOR_SWITCH:    // conveyor belts on/off
+      gd_sound_play(cave, GD_S_SWITCH_CONVEYOR, object, x, y);
+      cave->conveyor_belts_active = !cave->conveyor_belts_active;
+      return object;
+
+    case O_CONVEYOR_DIR_SWITCH: // conveyor belts switch direction
+      gd_sound_play(cave, GD_S_SWITCH_CONVEYOR, object, x, y);
+      cave->conveyor_belts_direction_changed = !cave->conveyor_belts_direction_changed;
+      return object;
+
+    // USUAL STUFF
+    case O_DIRT:
+    case O_DIRT2:
+    case O_STEEL_EATABLE:
+    case O_BRICK_EATABLE:
+    case O_DIRT_SLOPED_UP_RIGHT:
+    case O_DIRT_SLOPED_UP_LEFT:
+    case O_DIRT_SLOPED_DOWN_LEFT:
+    case O_DIRT_SLOPED_DOWN_RIGHT:
+    case O_DIRT_BALL:
+    case O_DIRT_LOOSE:
+      gd_sound_play(cave, GD_S_DIRT_WALKING, object, x, y);
+      return O_SPACE;
+
+    case O_SWEET:
+      gd_sound_play(cave, GD_S_SWEET_COLLECTING, object, x, y);
+      cave->sweet_eaten = TRUE;
+      return O_SPACE;
+
+    case O_PNEUMATIC_HAMMER:
+      gd_sound_play(cave, GD_S_PNEUMATIC_COLLECTING, object, x, y);
+      cave->got_pneumatic_hammer = TRUE;
+      return O_SPACE;
+
+    case O_CLOCK:
+      // bonus time
+      gd_sound_play(cave, GD_S_CLOCK_COLLECTING, object, x, y);
+      cave->time += cave->time_bonus * cave->timing_factor;
+      if (cave->time > cave->max_time * cave->timing_factor)
+       cave->time -= cave->max_time * cave->timing_factor;
+      // no space, rather a dirt remains there...
+      return O_DIRT;
+
+    case O_DIAMOND:
+    case O_FLYING_DIAMOND:
+      // prevent diamond sounds for O_SKELETON (see below)
+      if (x != -1 && y != -1)
+       gd_sound_play(cave, (object == O_DIAMOND ? GD_S_DIAMOND_COLLECTING :
+                            GD_S_FLYING_DIAMOND_COLLECTING), object, x, y);
+
+      cave->score += cave->diamond_value;
+      cave->diamonds_collected++;
+
+      if (cave->diamonds_needed == cave->diamonds_collected)
+      {
+       cave->gate_open = TRUE;
+
+       // extra is worth more points.
+       cave->diamond_value = cave->extra_diamond_value;
+
+       cave->gate_open_flash = 1;
+       cave->sound3 = GD_S_CRACKING;
+       gd_sound_play(cave, GD_S_CRACKING, O_OUTBOX, x, y);
+      }
+      return O_SPACE;
+
+    case O_SKELETON:
+      cave->skeletons_collected++;
+
+      // as if player got a diamond
+      for (i = 0; i < cave->skeletons_worth_diamonds; i++)
+       player_get_element(cave, O_DIAMOND, -1, -1);
+
+      // _after_ calling get_element for the fake diamonds, so we overwrite its sounds
+      gd_sound_play(cave, GD_S_SKELETON_COLLECTING, object, x, y);
+      return O_SPACE;
+
+    case O_OUTBOX:
+    case O_INVIS_OUTBOX:
+      cave->player_state = GD_PL_EXITED;    // player now exits the cave!
+      return O_SPACE;
+
+    case O_SPACE:
+    case O_LAVA:    // player goes into lava, as if it was space
+      gd_sound_play(cave, GD_S_EMPTY_WALKING, object, x, y);
+      return O_SPACE;
+
+    default:
+      // the object will remain there.
+      return object;
+  }
+}
+
+/*
+  process a crazy dream-style teleporter.
+  called from gd_cave_iterate, for a player or a player_bomb.
+  player is standing at px, py, and trying to move in the direction player_move,
+  where there is a teleporter at (tx_start, ty_start). we check the whole cave,
+  from (tx_start + 1, ty_start), till we get back to (tx_start, ty_start) (by wrapping
+  around). the first teleporter we find, and which is suitable, will be the destination.
+  return TRUE if teleporter worked, FALSE if cound not find any suitable teleporter.
+*/
+static boolean do_teleporter(GdCave *cave, int px, int py, GdDirection player_move)
+{
+  // start at teleporter position (not at player position!)
+  int tx_start = px + gd_dx[player_move];
+  int ty_start = py + gd_dy[player_move];
+  int tx = tx_start;
+  int ty = ty_start;
+
+  do
+  {
+    // jump to next element; wrap around columns and rows.
+    tx++;
+
+    if (tx >= cave->w)
+    {
+      tx = 0;
+      ty++;
+
+      if (ty >= cave->h)
+       ty = 0;
+    }
+
+    // if we found a teleporter...
+    if (get(cave, tx, ty) == O_TELEPORTER &&
+       is_space_dir(cave, tx, ty, player_move))
+    {
+      // new player appears near teleporter found
+      store_dir(cave, tx, ty, player_move, get(cave, px, py));
+
+      // current player disappears
+      store(cave, px, py, O_SPACE);
+
+      gd_sound_play(cave, GD_S_TELEPORTER, O_TELEPORTER, tx, ty);
+
+      return TRUE;    // return true as teleporter worked
+    }
+  }
+  // loop until we get back to original coordinates
+  while (tx != tx_start || ty != ty_start);
+
+  // return false as we did not find any usable teleporter
+  return FALSE;
+}
+
+/*
+  try to push an element.
+  returns true if the push is possible; also does move the specified _element_.
+  up to the caller to move the _player_itself_.
+*/
+static boolean do_push(GdCave *cave, int x, int y, GdDirection player_move, boolean player_fire)
+{
+  boolean result;
+  GdElement what = get_dir(cave, x, y, player_move);
+
+  // gravity for falling wall, bladder, ...
+  GdDirection grav_compat = cave->gravity_affects_all ? cave->gravity : GD_MV_DOWN;
+
+  result = FALSE;
+
+  switch (what)
+  {
+    case O_WAITING_STONE:
+    case O_STONE:
+    case O_NITRO_PACK:
+    case O_CHASING_STONE:
+    case O_MEGA_STONE:
+    case O_FLYING_STONE:
+    case O_NUT:
+      // pushing some kind of stone or nut
+      // directions possible: 90degrees cw or ccw to current gravity.
+      // only push if player dir is orthogonal to gravity,
+      // ie. gravity down, pushing left & right possible
+      if (player_move == ccw_fourth[cave->gravity] ||
+         player_move == cw_fourth[cave->gravity])
+      {
+       int prob;
+
+       prob = 0;
+
+       // different probabilities for different elements.
+       switch (what)
+       {
+         case O_WAITING_STONE:
+           // waiting stones are light, can always push
+           prob = 1000000;
+           break;
+
+         case O_CHASING_STONE:
+           // chasing can be pushed if player is turbo
+           if (cave->sweet_eaten)
+             prob = 1000000;
+           break;
+
+         case O_MEGA_STONE:
+           // mega may(!) be pushed if player is turbo
+           if (cave->mega_stones_pushable_with_sweet && cave->sweet_eaten)
+             prob = 1000000;
+           break;
+
+         case O_STONE:
+         case O_NUT:
+         case O_FLYING_STONE:
+         case O_NITRO_PACK:
+           if (cave->sweet_eaten)
+             prob = cave->pushing_stone_prob_sweet; // probability with sweet
+           else
+             prob = cave->pushing_stone_prob; // probability without sweet.
+           break;
+
+         default:
+           break;
+       }
+
+       if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move) &&
+           gd_rand_int_range(cave->random, 0, 1000000) < prob)
+       {
+         // if decided that he will be able to push,
+         store_dir(cave, x, y, GD_MV_TWICE + player_move, what);
+         play_sound_of_element_pushing(cave, what, x, y);
+         result = TRUE;
+       }
+      }
+      break;
+
+    case O_BLADDER:
+    case O_BLADDER_1:
+    case O_BLADDER_2:
+    case O_BLADDER_3:
+    case O_BLADDER_4:
+    case O_BLADDER_5:
+    case O_BLADDER_6:
+    case O_BLADDER_7:
+    case O_BLADDER_8:
+      // pushing a bladder. keep in mind that after pushing, we always get an O_BLADDER,
+      // not an O_BLADDER_x.
+      // there is no "delayed" state of a bladder, so we use store_dir_no_scanned!
+
+      // first check: we cannot push a bladder "up"
+      if (player_move != opposite[grav_compat])
+      {
+       // pushing a bladder "down". p = player, o = bladder, 1, 2, 3 = directions to check.
+       // player moving in the direction of gravity.
+       //  p   p  g
+       // 2o3  |  |
+       //  1   v  v
+       if (player_move == grav_compat)
+       {
+         // pushing bladder down
+         if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move))
+           store_dir_no_scanned(cave, x, y, GD_MV_TWICE + player_move, O_BLADDER), result = TRUE;
+         // if no space to push down, maybe left (down-left to player)
+         else if (is_space_dir(cave, x, y, cw_eighth[grav_compat]))
+
+           // left is "down, turned right (cw)"
+           store_dir_no_scanned(cave, x, y, cw_eighth[grav_compat], O_BLADDER), result = TRUE;
+         // if not, maybe right (down-right to player)
+         else if (is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
+           store_dir_no_scanned(cave, x, y, ccw_eighth[grav_compat], O_BLADDER), result = TRUE;
+       }
+
+       // pushing a bladder "left". p = player, o = bladder, 1, 2, 3 = directions to check.
+       //  3        g
+       // 1op  <-p  |
+       //  2        v
+       else if (player_move == cw_fourth[grav_compat])
+       {
+         if (is_space_dir(cave, x, y, GD_MV_TWICE + cw_fourth[grav_compat]))    // pushing it left
+           store_dir_no_scanned(cave, x, y, GD_MV_TWICE + cw_fourth[grav_compat], O_BLADDER), result = TRUE;
+         else if (is_space_dir(cave, x, y, cw_eighth[grav_compat]))    // maybe down, and player will move left
+           store_dir_no_scanned(cave, x, y, cw_eighth[grav_compat], O_BLADDER), result = TRUE;
+         else if (is_space_dir(cave, x, y, cw_eighth[player_move]))    // maybe up, and player will move left
+           store_dir_no_scanned(cave, x, y, cw_eighth[player_move], O_BLADDER), result = TRUE;
+       }
+
+       // pushing a bladder "right". p = player, o = bladder, 1, 2, 3 = directions to check.
+       //  3        g
+       // po1  p-<  |
+       //  2        v
+       else if (player_move == ccw_fourth[grav_compat])
+       {
+         if (is_space_dir(cave, x, y, GD_MV_TWICE + player_move))    // pushing it right
+           store_dir_no_scanned(cave, x, y, GD_MV_TWICE + player_move, O_BLADDER), result = TRUE;
+         else if (is_space_dir(cave, x, y, ccw_eighth[grav_compat]))    // maybe down, and player will move right
+           store_dir_no_scanned(cave, x, y, ccw_eighth[grav_compat], O_BLADDER), result = TRUE;
+         else if (is_space_dir(cave, x, y, ccw_eighth[player_move]))    // maybe up, and player will move right
+           store_dir_no_scanned(cave, x, y, ccw_eighth[player_move], O_BLADDER), result = TRUE;
+       }
+
+       if (result)
+         play_sound_of_element_pushing(cave, O_BLADDER, x, y);
+      }
+      break;
+
+    case O_BOX:
+      // a box is only pushed with the fire pressed
+      if (player_fire)
+      {
+       // but always with 100% probability
+       switch (player_move)
+       {
+         case GD_MV_LEFT:
+         case GD_MV_RIGHT:
+         case GD_MV_UP:
+         case GD_MV_DOWN:
+           // pushing in some dir, two steps in that dir - is there space?
+           if (is_space_dir(cave, x, y, player_move + GD_MV_TWICE))
+           {
+             // yes, so push.
+             store_dir(cave, x, y, player_move + GD_MV_TWICE, O_BOX);
+             result = TRUE;
+             gd_sound_play(cave, GD_S_BOX_PUSHING, what, x, y);
+           }
+           break;
+
+         default:
+           // push in no other directions possible
+           break;
+       }
+      }
+      break;
+
+      // pushing of other elements not possible
+    default:
+      break;
+  }
+
+  return result;
+}
+
+// from the key press booleans, create a direction
+GdDirection gd_direction_from_keypress(boolean up, boolean down, boolean left, boolean right)
+{
+  GdDirection player_move;
+
+  // from the key press booleans, create a direction
+  if (up && right)
+    player_move = GD_MV_UP_RIGHT;
+  else if (down && right)
+    player_move = GD_MV_DOWN_RIGHT;
+  else if (down && left)
+    player_move = GD_MV_DOWN_LEFT;
+  else if (up && left)
+    player_move = GD_MV_UP_LEFT;
+  else if (up)
+    player_move = GD_MV_UP;
+  else if (down)
+    player_move = GD_MV_DOWN;
+  else if (left)
+    player_move = GD_MV_LEFT;
+  else if (right)
+    player_move = GD_MV_RIGHT;
+  else
+    player_move = GD_MV_STILL;
+
+  return player_move;
+}
+
+// clear these to no sound; and they will be set during iteration.
+void gd_cave_clear_sounds(GdCave *cave)
+{
+  cave->sound1 = GD_S_NONE;
+  cave->sound2 = GD_S_NONE;
+  cave->sound3 = GD_S_NONE;
+}
+
+static void do_start_fall(GdCave *cave, int x, int y, GdDirection falling_direction,
+                         GdElement falling_element)
+{
+  if (cave->gravity_disabled)
+    return;
+
+  if (is_space_dir(cave, x, y, falling_direction))
+  {
+    // beginning to fall
+    play_sound_of_element(cave, get(cave, x, y), x, y);
+    move(cave, x, y, falling_direction, falling_element);
+  }
+
+  // check if it is on a sloped element, and it can roll.
+  // for example, sloped wall looks like:
+  //  /|
+  // /_|
+  // this is tagged as sloped up&left.
+  // first check if the stone or diamond is coming from "up" (ie. opposite of gravity)
+  // then check the direction to roll (left or right)
+  // this way, gravity can also be pointing right, and the above slope will work as one would expect
+  else if (sloped_dir(cave, x, y, falling_direction, opposite[falling_direction]))
+  {
+    // rolling down, if sitting on a sloped object
+    if (sloped_dir(cave, x, y, falling_direction, cw_fourth[falling_direction]) &&
+       is_space_dir(cave, x, y, cw_fourth[falling_direction]) &&
+       is_space_dir(cave, x, y, cw_eighth[falling_direction]))
+    {
+      // rolling left? - keep in mind that ccw_fourth rotates gravity ccw,
+      // so here we use cw_fourth
+      play_sound_of_element(cave, get(cave, x, y), x, y);
+      move(cave, x, y, cw_fourth[falling_direction], falling_element);
+    }
+    else if (sloped_dir(cave, x, y, falling_direction, ccw_fourth[falling_direction]) &&
+            is_space_dir(cave, x, y, ccw_fourth[falling_direction]) &&
+            is_space_dir(cave, x, y, ccw_eighth[falling_direction]))
+    {
+      // rolling right?
+      play_sound_of_element(cave, get(cave, x, y), x, y);
+      move(cave, x, y, ccw_fourth[falling_direction], falling_element);
+    }
+  }
+}
+
+static boolean do_fall_try_crush_voodoo(GdCave *cave, int x, int y, GdDirection fall_dir)
+{
+  if (get_dir(cave, x, y, fall_dir) == O_VOODOO &&
+      cave->voodoo_dies_by_stone)
+  {
+    // this is a 1stB-style vodo. explodes by stone, collects diamonds
+    explode_dir(cave, x, y, fall_dir);
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static boolean do_fall_try_eat_voodoo(GdCave *cave, int x, int y, GdDirection fall_dir)
+{
+  if (get_dir(cave, x, y, fall_dir) == O_VOODOO &&
+      cave->voodoo_collects_diamonds)
+  {
+    // this is a 1stB-style voodoo. explodes by stone, collects diamonds
+    player_get_element(cave, O_DIAMOND, x, y);   // as if player got diamond
+    store(cave, x, y, O_SPACE);    // diamond disappears
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static boolean do_fall_try_crack_nut(GdCave *cave, int x, int y,
+                                    GdDirection fall_dir, GdElement bouncing)
+{
+  if (get_dir(cave, x, y, fall_dir) == O_NUT ||
+      get_dir(cave, x, y, fall_dir) == O_NUT_F)
+  {
+    // stones
+    store(cave, x, y, bouncing);
+    store_dir(cave, x, y, fall_dir, cave->nut_turns_to_when_crushed);
+
+    gd_sound_play(cave, GD_S_NUT_CRACKING, O_NUT, x, y);
+
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static boolean do_fall_try_magic(GdCave *cave, int x, int y,
+                                GdDirection fall_dir, GdElement magic)
+{
+  if (get_dir(cave, x, y, fall_dir) == O_MAGIC_WALL)
+  {
+    play_sound_of_element(cave, O_DIAMOND, x, y);    // always play diamond sound
+
+    if (cave->magic_wall_state == GD_MW_DORMANT)
+      cave->magic_wall_state = GD_MW_ACTIVE;
+
+    if (cave->magic_wall_state == GD_MW_ACTIVE &&
+       is_space_dir(cave, x, y, GD_MV_TWICE+fall_dir))
+    {
+      // if magic wall active and place underneath, it turns element
+      // into anything the effect says to do.
+      store_dir(cave, x, y, GD_MV_TWICE+fall_dir, magic);
+    }
+
+    // active or non-active or anything, element falling in will always disappear
+    store(cave, x, y, O_SPACE);
+
+    if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE)
+      cave->convert_amoeba_this_frame = TRUE;
+
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static boolean do_fall_try_crush(GdCave *cave, int x, int y, GdDirection fall_dir)
+{
+  if (explodes_by_hit_dir(cave, x, y, fall_dir))
+  {
+    explode_dir(cave, x, y, fall_dir);
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+static boolean do_fall_roll_or_stop(GdCave *cave, int x, int y,
+                                   GdDirection fall_dir, GdElement bouncing)
+{
+  if (is_space_dir(cave, x, y, fall_dir))
+  {
+    // falling further
+    move(cave, x, y, fall_dir, get(cave, x, y));
+
+    return TRUE;
+  }
+
+  // check if it is on a sloped element, and it can roll.
+  // for example, sloped wall looks like:
+  //  /|
+  // /_|
+  // this is tagged as sloped up&left.
+  // first check if the stone or diamond is coming from "up" (ie. opposite of gravity)
+  // then check the direction to roll (left or right)
+  // this way, gravity can also be pointing right, and the above slope will work as one would expect
+
+  if (sloped_dir(cave, x, y, fall_dir, opposite[fall_dir]))
+  {
+    // sloped element, falling to left or right
+    if (sloped_dir(cave, x, y, fall_dir, cw_fourth[fall_dir]) &&
+       is_space_dir(cave, x, y, cw_eighth[fall_dir]) &&
+       is_space_dir(cave, x, y, cw_fourth[fall_dir]))
+    {
+      play_sound_of_element(cave, get(cave, x, y), x, y);
+
+      // try to roll left first - see O_STONE to understand why cw_fourth
+      move(cave, x, y, cw_fourth[fall_dir], get(cave, x, y));
+    }
+    else if (sloped_dir(cave, x, y, fall_dir, ccw_fourth[fall_dir]) &&
+            is_space_dir(cave, x, y, ccw_eighth[fall_dir]) &&
+            is_space_dir(cave, x, y, ccw_fourth[fall_dir]))
+    {
+      play_sound_of_element(cave, get(cave, x, y), x, y);
+
+      // if not, try to roll right
+      move(cave, x, y, ccw_fourth[fall_dir], get(cave, x, y));
+    }
+    else
+    {
+      // cannot roll in any direction, so it stops
+      play_sound_of_element(cave, get(cave, x, y), x, y);
+      store(cave, x, y, bouncing);
+    }
+
+    return TRUE;
+  }
+
+  // any other element, stops
+  play_sound_of_element(cave, get(cave, x, y), x, y);
+  store(cave, x, y, bouncing);
+  return TRUE;
+}
+
+static void update_cave_speed(GdCave *cave)
+{
+  // update timing calculated by iterating and counting elements which were slow to process on c64
+  switch (cave->scheduling)
+  {
+    case GD_SCHEDULING_MILLISECONDS:
+      // cave->speed already contains the milliseconds value, do not touch it
+      break;
+
+    case GD_SCHEDULING_BD1:
+      if (!cave->intermission)
+       // non-intermissions
+       cave->speed = (88 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
+      else
+       // intermissions were quicker, as only lines 1-12 were processed by the engine.
+       cave->speed = (60 + 3.66 * cave->c64_timing + (cave->ckdelay + cave->ckdelay_extra_for_animation) / 1000);
+      break;
+
+    case GD_SCHEDULING_BD1_ATARI:
+      // about 20ms/frame faster than c64 version
+      if (!cave->intermission)
+       cave->speed = (74 + 3.2 * cave->c64_timing + (cave->ckdelay) / 1000);            // non-intermissions
+      else
+       cave->speed = (65 + 2.88 * cave->c64_timing + (cave->ckdelay) / 1000);        // for intermissions
+      break;
+
+    case GD_SCHEDULING_BD2:
+      // 60 is a guess.
+      cave->speed = MAX(60 + (cave->ckdelay + cave->ckdelay_extra_for_animation)/1000, cave->c64_timing * 20);
+      break;
+
+    case GD_SCHEDULING_PLCK:
+      // 65 is totally empty cave in construction kit, with delay = 0)
+      cave->speed = MAX(65 + cave->ckdelay / 1000, cave->c64_timing * 20);
+      break;
+
+    case GD_SCHEDULING_BD2_PLCK_ATARI:
+      // a really fast engine; timing works like c64 plck.
+      // 40 ms was measured in the construction kit, with delay = 0
+      cave->speed = MAX(40 + cave->ckdelay / 1000, cave->c64_timing * 20);
+      break;
+
+    case GD_SCHEDULING_CRDR:
+      if (cave->hammered_walls_reappear) // this made the engine very slow.
+       cave->ckdelay += 60000;
+      cave->speed = MAX(130 + cave->ckdelay / 1000, cave->c64_timing * 20);
+      break;
+
+    case GD_SCHEDULING_MAX:
+      break;
+  }
+}
+
+// process a cave.
+void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, boolean suicide)
+{
+  int x, y, i;
+
+  // for border scan
+  int ymin, ymax;
+
+  // amoeba found to be enclosed. if not, this is cleared
+  boolean amoeba_found_enclosed, amoeba_2_found_enclosed;
+
+  // counting the number of amoebas. after scan, check if too much
+  int amoeba_count, amoeba_2_count;
+
+  // cave scan found water - for sound
+  boolean found_water;
+
+  boolean inbox_toggle;
+  boolean start_signal;
+
+  // gravity for falling wall, bladder, ...
+  GdDirection grav_compat = cave->gravity_affects_all ? cave->gravity : GD_MV_DOWN;
+
+  // directions for o_something_1, 2, 3 and 4 (creatures)
+  static const GdDirection creature_dir[] =
+  {
+    GD_MV_LEFT,
+    GD_MV_UP,
+    GD_MV_RIGHT,
+    GD_MV_DOWN
+  };
+  static const GdDirection creature_chdir[] =
+  {
+    GD_MV_RIGHT,
+    GD_MV_DOWN,
+    GD_MV_LEFT,
+    GD_MV_UP
+  };
+  int time_decrement_sec;
+
+  // biters eating elements preference, they try to go in this order
+  GdElement biter_try[] =
+  {
+    O_DIRT,
+    cave->biter_eat,
+    O_SPACE, O_STONE
+  };
+
+  boolean amoeba_sound, magic_sound;
+
+  gd_cave_clear_sounds(cave);
+
+  // if diagonal movements not allowed,
+  // horizontal movements have precedence. [BROADRIBB]
+  if (!cave->diagonal_movements)
+  {
+    switch (player_move)
+    {
+      case GD_MV_UP_RIGHT:
+      case GD_MV_DOWN_RIGHT:
+       player_move = GD_MV_RIGHT;
+       break;
+
+      case GD_MV_UP_LEFT:
+      case GD_MV_DOWN_LEFT:
+       player_move = GD_MV_LEFT;
+       break;
+
+      default:
+       // no correction needed
+       break;
+    }
+  }
+
+  // set cave get function; to implement perfect or lineshifting borders
+  if (cave->lineshift)
+  {
+    cave->getp = getp_shift;
+    cave->getx = getx_shift;
+    cave->gety = gety_shift;
+  }
+  else
+  {
+    cave->getp = getp_perfect;
+    cave->getx = getx_perfect;
+    cave->gety = gety_perfect;
+  }
+
+  // increment this. if the scan routine comes across player, clears it (sets to zero).
+  if (cave->player_seen_ago < 100)
+    cave->player_seen_ago++;
+
+  if (cave->pneumatic_hammer_active_delay > 0)
+    cave->pneumatic_hammer_active_delay--;
+
+  // inboxes and outboxes flash with the rhythm of the game, not the display.
+  // also, a player can be born only from an open, not from a steel-wall-like inbox.
+  cave->inbox_flash_toggle = !cave->inbox_flash_toggle;
+  inbox_toggle = cave->inbox_flash_toggle;
+
+  if (cave->gate_open_flash > 0)
+    cave->gate_open_flash--;
+
+  // score collected this frame
+  cave->score = 0;
+
+  // to implement buggy bd1 amoeba+magic wall behaviour
+  cave->convert_amoeba_this_frame = FALSE;
+
+  // suicide only kills the active player
+  // player_x, player_y was set by the previous iterate routine, or the cave setup.
+  // we must check if there is a player or not - he may have exploded or something like that
+  if (suicide && cave->player_state == GD_PL_LIVING &&
+      is_player(cave, cave->player_x, cave->player_y))
+    store(cave, cave->player_x, cave->player_y, O_EXPLODE_1);
+
+  // check for walls reappearing
+  if (cave->hammered_reappear)
+  {
+    for (y = 0; y < cave->h; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       // timer for the cell > 0?
+       if (cave->hammered_reappear[y][x] > 0)
+       {
+         // decrease timer
+         cave->hammered_reappear[y][x]--;
+
+         // check if it became zero
+         if (cave->hammered_reappear[y][x] == 0)
+         {
+           store(cave, x, y, O_BRICK);
+           gd_sound_play(cave, GD_S_WALL_REAPPEARING, O_BRICK, x, y);
+         }
+       }
+      }
+    }
+  }
+
+  // variables to check during the scan
+
+  // will be set to false if any of the amoeba is found free.
+  amoeba_found_enclosed = TRUE;
+  amoeba_2_found_enclosed = TRUE;
+  amoeba_count = 0;
+  amoeba_2_count = 0;
+  found_water = FALSE;
+  cave->ckdelay = 0;
+  time_decrement_sec = 0;
+
+  // check whether to scan the first and last line
+  if (cave->border_scan_first_and_last)
+  {
+    ymin = 0;
+    ymax = cave->h - 1;
+  }
+  else
+  {
+    ymin = 1;
+    ymax = cave->h - 2;
+  }
+
+  // the cave scan routine
+  for (y = ymin; y <= ymax; y++)
+  {
+    for (x = 0; x < cave->w; x++)
+    {
+      // if we find a scanned element, change it to the normal one, and that's all.
+      // this is required, for example for chasing stones, which have moved, always passing slime!
+      if (get(cave, x, y) & SCANNED)
+      {
+       store(cave, x, y, get(cave, x, y) & ~SCANNED);
+
+       continue;
+      }
+
+      // add the ckdelay correction value for every element seen.
+      cave->ckdelay += gd_elements[get(cave, x, y)].ckdelay;
+
+      switch (get(cave, x, y))
+      {
+       // ============================================================================
+       //    P L A Y E R S
+       // ============================================================================
+
+       case O_PLAYER:
+         if (cave->kill_player)
+         {
+           explode (cave, x, y);
+           break;
+         }
+
+         cave->player_seen_ago = 0;
+         // bd4 intermission caves have many players. so if one of them has exited,
+         // do not change the flag anymore. so this if () is needed
+         if (cave->player_state != GD_PL_EXITED)
+           cave->player_state = GD_PL_LIVING;
+
+         // check for pneumatic hammer things
+         // 1) press fire, 2) have pneumatic hammer 4) space on left or right
+         // for hammer 5) stand on something
+         if (player_fire && cave->got_pneumatic_hammer &&
+             is_space_dir(cave, x, y, player_move) &&
+             !is_space_dir(cave, x, y, GD_MV_DOWN))
+         {
+           if (player_move == GD_MV_LEFT &&
+               can_be_hammered_dir(cave, x, y, GD_MV_DOWN_LEFT))
+           {
+             cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
+             store_dir(cave, x, y, GD_MV_LEFT, O_PNEUMATIC_ACTIVE_LEFT);
+             store(cave, x, y, O_PLAYER_PNEUMATIC_LEFT);
+             break;    // finished.
+           }
+
+           if (player_move == GD_MV_RIGHT &&
+               can_be_hammered_dir(cave, x, y, GD_MV_DOWN_RIGHT))
+           {
+             cave->pneumatic_hammer_active_delay = cave->pneumatic_hammer_frame;
+             store_dir(cave, x, y, GD_MV_RIGHT, O_PNEUMATIC_ACTIVE_RIGHT);
+             store(cave, x, y, O_PLAYER_PNEUMATIC_RIGHT);
+             break;    // finished.
+           }
+         }
+
+         if (player_move != GD_MV_STILL)
+         {
+           // only do every check if he is not moving
+           GdElement what = get_dir(cave, x, y, player_move);
+           GdElement remains = what;
+           boolean push;
+
+           // if we are 'eating' a teleporter, and the function returns true
+           // (teleporting worked), break here
+           if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
+             break;
+
+           // try to push element; if successful, break
+           push = do_push(cave, x, y, player_move, player_fire);
+           if (push)
+           {
+             remains = O_SPACE;
+           }
+           else
+           {
+             switch (what)
+             {
+               case O_BOMB:
+                 // if its a bomb, remember he now has one.
+                 // we do not change the "remains" and "what" variables,
+                 // so that part of the code will be ineffective
+                 gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
+                 store_dir(cave, x, y, player_move, O_SPACE);
+
+                 if (player_fire)
+                   store(cave, x, y, O_PLAYER_BOMB);
+                 else
+                   move(cave, x, y, player_move, O_PLAYER_BOMB);
+                 break;
+
+               case O_ROCKET_LAUNCHER:
+                 // if its a rocket launcher, remember he now has one.
+                 // we do not change the "remains" and "what" variables,
+                 // so that part of the code will be ineffective
+                 gd_sound_play(cave, GD_S_BOMB_COLLECTING, what, x, y);
+                 store_dir(cave, x, y, player_move, O_SPACE);
+
+                 if (player_fire)
+                   store(cave, x, y, O_PLAYER_ROCKET_LAUNCHER);
+                 else
+                   move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
+                 break;
+
+               case O_POT:
+                 // we do not change the "remains" and "what" variables,
+                 // so that part of the code will be ineffective
+                 if (!player_fire && !cave->gravity_switch_active &&
+                     cave->skeletons_collected >= cave->skeletons_needed_for_pot)
+                 {
+                   cave->skeletons_collected -= cave->skeletons_needed_for_pot;
+                   move(cave, x, y, player_move, O_PLAYER_STIRRING);
+                   cave->gravity_disabled = TRUE;
+                 }
+                 break;
+
+               case O_GRAVITY_SWITCH:
+                 // (we cannot use player_get for this as it does not have player_move parameter)
+                 // only allow changing direction if the new dir is not diagonal
+                 if (cave->gravity_switch_active &&
+                     (player_move == GD_MV_LEFT ||
+                      player_move == GD_MV_RIGHT ||
+                      player_move == GD_MV_UP ||
+                      player_move == GD_MV_DOWN))
+                 {
+                   gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
+                   cave->gravity_will_change =
+                     cave->gravity_change_time * cave->timing_factor;
+                   cave->gravity_next_direction = player_move;
+                   cave->gravity_switch_active = FALSE;
+                 }
+                 break;
+
+               default:
+                 // get element - process others.
+                 // if cannot get, player_get_element will return the same
+                 remains = player_get_element(cave, what, x, y);
+                 break;
+             }
+           }
+
+           if (remains != what || remains == O_SPACE)
+           {
+             // if anything changed, apply the change.
+
+             // 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;
+
+             if (remains != O_SPACE || player_fire)
+               // if any other element than space, player cannot move.
+               // also if pressing fire, will not move.
+               store_dir(cave, x, y, player_move, remains);
+             else
+               // if space remains there, the player moves.
+               move(cave, x, y, player_move, O_PLAYER);
+           }
+         }
+         break;
+
+       case O_PLAYER_BOMB:
+         // much simpler; cannot steal stones
+         if (cave->kill_player)
+         {
+           explode(cave, x, y);
+           break;
+         }
+
+         cave->player_seen_ago = 0;
+         // bd4 intermission caves have many players. so if one of them has exited,
+         // do not change the flag anymore. so this if () is needed
+         if (cave->player_state != GD_PL_EXITED)
+           cave->player_state = GD_PL_LIVING;
+
+         if (player_move != GD_MV_STILL)
+         {
+           // if the player does not move, nothing to do
+           GdElement what = get_dir(cave, x, y, player_move);
+           GdElement remains = what;
+
+           if (player_fire)
+           {
+             // placing a bomb into empty space or dirt
+             if (is_space_dir(cave, x, y, player_move) ||
+                 is_element_dir(cave, x, y, player_move, O_DIRT))
+             {
+               store_dir(cave, x, y, player_move, O_BOMB_TICK_1);
+
+               // placed bomb, he is normal player again
+               store(cave, x, y, O_PLAYER);
+               gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
+             }
+             break;
+           }
+
+           // pushing and collecting
+           // if we are 'eating' a teleporter, and the function returns true
+           // (teleporting worked), break here
+           if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
+             break;
+
+           // player fire is false...
+           if (do_push(cave, x, y, player_move, FALSE))
+           {
+             remains = O_SPACE;
+           }
+           else
+           {
+             switch (what)
+             {
+               case O_GRAVITY_SWITCH:
+                 // (we cannot use player_get for this as it does not have
+                 // player_move parameter)
+                 // only allow changing direction if the new dir is not diagonal
+                 if (cave->gravity_switch_active &&
+                     (player_move == GD_MV_LEFT ||
+                      player_move == GD_MV_RIGHT ||
+                      player_move == GD_MV_UP ||
+                      player_move == GD_MV_DOWN))
+                 {
+                   gd_sound_play(cave, GD_S_SWITCH_GRAVITY, what, x, y);
+                   cave->gravity_will_change =
+                     cave->gravity_change_time * cave->timing_factor;
+                   cave->gravity_next_direction = player_move;
+                   cave->gravity_switch_active = FALSE;
+                 }
+                 break;
+
+               default:
+                 // get element. if cannot get, player_get_element will return the same
+                 remains = player_get_element (cave, what, x, y);
+                 break;
+             }
+           }
+
+           // if element changed, OR there is space, move.
+           if (remains != what || remains == O_SPACE)
+           {
+             // if anything changed, apply the change.
+             move(cave, x, y, player_move, O_PLAYER_BOMB);
+           }
+         }
+         break;
+
+       case O_PLAYER_ROCKET_LAUNCHER:
+         // much simpler; cannot snap-push stones
+         if (cave->kill_player)
+         {
+           explode(cave, x, y);
+           break;
+         }
+
+         cave->player_seen_ago = 0;
+         // bd4 intermission caves have many players. so if one of them has exited,
+         // do not change the flag anymore. so this if () is needed
+         if (cave->player_state != GD_PL_EXITED)
+           cave->player_state = GD_PL_LIVING;
+
+         // firing a rocket?
+         if (player_move != GD_MV_STILL)
+         {
+           // if the player does not move, nothing to do
+           GdElement what = get_dir(cave, x, y, player_move);
+           GdElement remains = what;
+
+           // to fire a rocket, diagonal movement should not be allowed.
+           // so either x or y must be zero
+           if (player_fire)
+           {
+             // placing a rocket into empty space
+             if (is_space_dir(cave, x, y, player_move))
+             {
+               switch (player_move)
+               {
+                 case GD_MV_RIGHT:
+                   store_dir(cave, x, y, player_move, O_ROCKET_1);
+                   if (!cave->infinite_rockets)
+                     store(cave, x, y, O_PLAYER);
+                   break;
+
+                 case GD_MV_UP:
+                   store_dir(cave, x, y, player_move, O_ROCKET_2);
+                   if (!cave->infinite_rockets)
+                     store(cave, x, y, O_PLAYER);
+                   break;
+
+                 case GD_MV_LEFT:
+                   store_dir(cave, x, y, player_move, O_ROCKET_3);
+                   if (!cave->infinite_rockets)
+                     store(cave, x, y, O_PLAYER);
+                   break;
+
+                 case GD_MV_DOWN:
+                   store_dir(cave, x, y, player_move, O_ROCKET_4);
+                   if (!cave->infinite_rockets)
+                     store(cave, x, y, O_PLAYER);
+                   break;
+
+                 default:
+                   // cannot fire in other directions
+                   break;
+               }
+
+               gd_sound_play(cave, GD_S_BOMB_PLACING, O_BOMB, x, y);
+             }
+
+             // a player with rocket launcher cannot snap elements, so stop here
+             break;
+           }
+
+           // pushing and collecting
+           // if we are 'eating' a teleporter, and the function returns true
+           // (teleporting worked), break here
+           if (what == O_TELEPORTER && do_teleporter(cave, x, y, player_move))
+             break;
+
+           // player fire is false...
+           if (do_push(cave, x, y, player_move, FALSE))
+           {
+             remains = O_SPACE;
+           }
+           else
+           {
+             // get element. if cannot get, player_get_element will return the same
+             remains = player_get_element(cave, what, x, y);
+           }
+
+           // if something changed, OR there is space, move.
+           if (remains != what || remains == O_SPACE)
+           {
+             // if anything changed, apply the change.
+             move(cave, x, y, player_move, O_PLAYER_ROCKET_LAUNCHER);
+           }
+         }
+         break;
+
+       case O_PLAYER_STIRRING:
+         if (cave->kill_player)
+         {
+           explode(cave, x, y);
+           break;
+         }
+
+         // stirring sound, if no other walking sound or explosion
+         gd_sound_play(cave, GD_S_STIRRING, O_PLAYER_STIRRING, x, y);
+
+         cave->player_seen_ago = 0;
+         // bd4 intermission caves have many players. so if one of them has exited,
+         // do not change the flag anymore. so this if () is needed
+         if (cave->player_state != GD_PL_EXITED)
+           cave->player_state = GD_PL_LIVING;
+
+         if (player_fire)
+         {
+           // player "exits" stirring the pot by pressing fire
+           cave->gravity_disabled = FALSE;
+           store(cave, x, y, O_PLAYER);
+           cave->gravity_switch_active = TRUE;
+         }
+         break;
+
+         // player holding pneumatic hammer
+       case O_PLAYER_PNEUMATIC_LEFT:
+       case O_PLAYER_PNEUMATIC_RIGHT:
+         // usual player stuff
+         if (cave->kill_player)
+         {
+           explode(cave, x, y);
+           break;
+         }
+
+         cave->player_seen_ago = 0;
+         if (cave->player_state != GD_PL_EXITED)
+           cave->player_state = GD_PL_LIVING;
+
+         // if hammering time is up, becomes a normal player again.
+         if (cave->pneumatic_hammer_active_delay == 0)
+           store(cave, x, y, O_PLAYER);
+         break;
+
+         // the active pneumatic hammer itself
+       case O_PNEUMATIC_ACTIVE_RIGHT:
+       case O_PNEUMATIC_ACTIVE_LEFT:
+         if (cave->pneumatic_hammer_active_delay == 0)
+         {
+           GdElement new_elem;
+
+           // pneumatic hammer element disappears
+           store(cave, x, y, O_SPACE);
+
+           // which is the new element which appears after that one is hammered?
+           new_elem = gd_element_get_hammered(get_dir(cave, x, y, GD_MV_DOWN));
+
+           // if there is a new element, display it
+           // O_NONE might be returned, for example if the element being
+           // hammered explodes during hammering (by a nearby explosion)
+           if (new_elem != O_NONE)
+           {
+             store_dir(cave, x, y, GD_MV_DOWN, new_elem);
+
+             // and if walls reappear, remember it in array
+             if (cave->hammered_walls_reappear)
+             {
+               int wall_y;
+
+               wall_y = (y + 1) % cave->h;
+               cave->hammered_reappear[wall_y][x] = cave->hammered_wall_reappear_frame;
+             }
+           }
+         }
+         break;
+
+         // ============================================================================
+         //    S T O N E S,   D I A M O N D S
+         // ============================================================================
+
+       case O_STONE:           // standing stone
+         do_start_fall(cave, x, y, cave->gravity, cave->stone_falling_effect);
+         break;
+
+       case O_MEGA_STONE:      // standing mega_stone
+         do_start_fall(cave, x, y, cave->gravity, O_MEGA_STONE_F);
+         break;
+
+       case O_DIAMOND:         // standing diamond
+         do_start_fall(cave, x, y, cave->gravity, cave->diamond_falling_effect);
+         break;
+
+       case O_NUT:             // standing nut
+         do_start_fall(cave, x, y, cave->gravity, O_NUT_F);
+         break;
+
+       case O_DIRT_BALL:       // standing dirt ball
+         do_start_fall(cave, x, y, cave->gravity, O_DIRT_BALL_F);
+         break;
+
+       case O_DIRT_LOOSE:      // standing loose dirt
+         do_start_fall(cave, x, y, cave->gravity, O_DIRT_LOOSE_F);
+         break;
+
+       case O_FLYING_STONE:    // standing stone
+         do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_STONE_F);
+         break;
+
+       case O_FLYING_DIAMOND:  // standing diamond
+         do_start_fall(cave, x, y, opposite[cave->gravity], O_FLYING_DIAMOND_F);
+         break;
+
+         // ============================================================================
+         //    F A L L I N G    E L E M E N T S,    F L Y I N G   S T O N E S,   D I A M O N D S
+         // ============================================================================
+
+       case O_DIRT_BALL_F:     // falling dirt ball
+         if (!cave->gravity_disabled)
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_BALL);
+         break;
+
+       case O_DIRT_LOOSE_F:    // falling loose dirt
+         if (!cave->gravity_disabled)
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, O_DIRT_LOOSE);
+         break;
+
+       case O_STONE_F:         // falling stone
+         if (!cave->gravity_disabled)
+         {
+           if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
+             break;
+
+           if (do_fall_try_crack_nut(cave, x, y, cave->gravity, cave->stone_bouncing_effect))
+             break;
+
+           if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_stone_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, cave->gravity))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->stone_bouncing_effect);
+         }
+         break;
+
+       case O_MEGA_STONE_F:    // falling mega
+         if (!cave->gravity_disabled)
+         {
+           if (do_fall_try_crush_voodoo(cave, x, y, cave->gravity))
+             break;
+
+           if (do_fall_try_crack_nut(cave, x, y, cave->gravity, O_MEGA_STONE))
+             break;
+
+           if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_mega_stone_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, cave->gravity))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, O_MEGA_STONE);
+         }
+         break;
+
+       case O_DIAMOND_F:       // falling diamond
+         if (!cave->gravity_disabled)
+         {
+           if (do_fall_try_eat_voodoo(cave, x, y, cave->gravity))
+             break;
+
+           if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_diamond_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, cave->gravity))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, cave->diamond_bouncing_effect);
+         }
+         break;
+
+       case O_NUT_F:           // falling nut
+         if (!cave->gravity_disabled)
+         {
+           if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nut_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, cave->gravity))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, cave->gravity, O_NUT);
+         }
+         break;
+
+       case O_FLYING_STONE_F:  // falling stone
+         if (!cave->gravity_disabled)
+         {
+           GdDirection fall_dir = opposite[cave->gravity];
+
+           if (do_fall_try_crush_voodoo(cave, x, y, fall_dir))
+             break;
+
+           if (do_fall_try_crack_nut(cave, x, y, fall_dir, O_FLYING_STONE))
+             break;
+
+           if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_stone_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, fall_dir))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_STONE);
+         }
+         break;
+
+       case O_FLYING_DIAMOND_F:    // falling diamond
+         if (!cave->gravity_disabled)
+         {
+           GdDirection fall_dir = opposite[cave->gravity];
+
+           if (do_fall_try_eat_voodoo(cave, x, y, fall_dir))
+             break;
+
+           if (do_fall_try_magic(cave, x, y, fall_dir, cave->magic_flying_diamond_to))
+             break;
+
+           if (do_fall_try_crush(cave, x, y, fall_dir))
+             break;
+
+           do_fall_roll_or_stop(cave, x, y, fall_dir, O_FLYING_DIAMOND);
+         }
+         break;
+
+         // ============================================================================
+         //    N I T R O    P A C K
+         // ============================================================================
+
+       case O_NITRO_PACK:      // standing nitro pack
+         do_start_fall(cave, x, y, cave->gravity, O_NITRO_PACK_F);
+         break;
+
+       case O_NITRO_PACK_F:    // falling nitro pack
+         if (!cave->gravity_disabled)
+         {
+           if (is_space_dir(cave, x, y, cave->gravity))    // if space, falling further
+             move(cave, x, y, cave->gravity, get(cave, x, y));
+           else if (do_fall_try_magic(cave, x, y, cave->gravity, cave->magic_nitro_pack_to))
+           {
+             // try magic wall; if true, function did the work
+           }
+           else if (is_element_dir(cave, x, y, cave->gravity, O_DIRT))
+           {
+             // falling on a dirt, it does NOT explode - just stops at its place.
+             play_sound_of_element(cave, O_NITRO_PACK, x, y);
+             store(cave, x, y, O_NITRO_PACK);
+           }
+           else
+             // falling on any other element it explodes
+             explode(cave, x, y);
+         }
+         break;
+
+       case O_NITRO_PACK_EXPLODE:    // a triggered nitro pack
+         explode(cave, x, y);
+         break;
+
+         // ============================================================================
+         //    C R E A T U R E S
+         // ============================================================================
+
+       case O_COW_1:
+       case O_COW_2:
+       case O_COW_3:
+       case O_COW_4:
+         // if cannot move in any direction, becomes an enclosed cow
+         if (!is_space_dir(cave, x, y, GD_MV_UP) && !is_space_dir(cave, x, y, GD_MV_DOWN) &&
+             !is_space_dir(cave, x, y, GD_MV_LEFT) && !is_space_dir(cave, x, y, GD_MV_RIGHT))
+           store(cave, x, y, O_COW_ENCLOSED_1);
+         else
+         {
+           // THIS IS THE CREATURE MOVE thing copied.
+           const GdDirection *creature_move;
+           boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
+           GdElement base;    // base element number (which is like O_***_1)
+           int dir, dirn, dirp;    // direction
+
+           base = O_COW_1;
+
+           dir = get(cave, x, y)-base;    // facing where
+           creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
+
+           // now change direction if backwards
+           if (cave->creatures_backwards)
+             ccw = !ccw;
+
+           if (ccw)
+           {
+             dirn = (dir + 3) & 3;    // fast turn
+             dirp = (dir + 1) & 3;    // slow turn
+           }
+           else
+           {
+             dirn = (dir + 1) & 3;    // fast turn
+             dirp = (dir + 3) & 3;    // slow turn
+           }
+
+           if (is_space_dir(cave, x, y, creature_move[dirn]))
+             move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
+           else if (is_space_dir(cave, x, y, creature_move[dir]))
+             move(cave, x, y, creature_move[dir], base + dir);    // go on
+           else
+             store(cave, x, y, base + dirp);    // turn in place if nothing else possible
+         }
+         break;
+
+         // enclosed cows wait some time before turning to a skeleton
+       case O_COW_ENCLOSED_1:
+       case O_COW_ENCLOSED_2:
+       case O_COW_ENCLOSED_3:
+       case O_COW_ENCLOSED_4:
+       case O_COW_ENCLOSED_5:
+       case O_COW_ENCLOSED_6:
+         if (is_space_dir(cave, x, y, GD_MV_UP) ||
+             is_space_dir(cave, x, y, GD_MV_LEFT) ||
+             is_space_dir(cave, x, y, GD_MV_RIGHT) ||
+             is_space_dir(cave, x, y, GD_MV_DOWN))
+           store(cave, x, y, O_COW_1);
+         else
+           next(cave, x, y);
+         break;
+
+       case O_COW_ENCLOSED_7:
+         if (is_space_dir(cave, x, y, GD_MV_UP) ||
+             is_space_dir(cave, x, y, GD_MV_LEFT) ||
+             is_space_dir(cave, x, y, GD_MV_RIGHT) ||
+             is_space_dir(cave, x, y, GD_MV_DOWN))
+           store(cave, x, y, O_COW_1);
+         else
+           store(cave, x, y, O_SKELETON);
+         break;
+
+       case O_FIREFLY_1:
+       case O_FIREFLY_2:
+       case O_FIREFLY_3:
+       case O_FIREFLY_4:
+       case O_ALT_FIREFLY_1:
+       case O_ALT_FIREFLY_2:
+       case O_ALT_FIREFLY_3:
+       case O_ALT_FIREFLY_4:
+       case O_BUTTER_1:
+       case O_BUTTER_2:
+       case O_BUTTER_3:
+       case O_BUTTER_4:
+       case O_ALT_BUTTER_1:
+       case O_ALT_BUTTER_2:
+       case O_ALT_BUTTER_3:
+       case O_ALT_BUTTER_4:
+       case O_STONEFLY_1:
+       case O_STONEFLY_2:
+       case O_STONEFLY_3:
+       case O_STONEFLY_4:
+         // check if touches a voodoo
+         if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
+           cave->voodoo_touched = TRUE;
+
+         // check if touches something bad and should explode (includes voodoo by the flags)
+         if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
+           explode (cave, x, y);
+         // otherwise move
+         else
+         {
+           const GdDirection *creature_move;
+           boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
+           GdElement base = -1;    // base element number (which is like O_***_1)
+           int dir, dirn, dirp;    // direction
+
+           if (get(cave, x, y) >= O_FIREFLY_1 &&
+               get(cave, x, y) <= O_FIREFLY_4)
+             base = O_FIREFLY_1;
+           else if (get(cave, x, y) >= O_BUTTER_1 &&
+                    get(cave, x, y) <= O_BUTTER_4)
+             base = O_BUTTER_1;
+           else if (get(cave, x, y) >= O_STONEFLY_1 &&
+                    get(cave, x, y) <= O_STONEFLY_4)
+             base = O_STONEFLY_1;
+           else if (get(cave, x, y) >= O_ALT_FIREFLY_1 &&
+                    get(cave, x, y) <= O_ALT_FIREFLY_4)
+             base = O_ALT_FIREFLY_1;
+           else if (get(cave, x, y) >= O_ALT_BUTTER_1 &&
+                    get(cave, x, y) <= O_ALT_BUTTER_4)
+             base = O_ALT_BUTTER_1;
+
+           dir = get(cave, x, y) - base;    // facing where
+           creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
+
+           // now change direction if backwards
+           if (cave->creatures_backwards)
+             ccw = !ccw;
+
+           if (ccw)
+           {
+             dirn = (dir + 3) & 3;    // fast turn
+             dirp = (dir + 1) & 3;    // slow turn
+           }
+           else
+           {
+             dirn = (dir + 1) & 3;    // fast turn
+             dirp = (dir + 3) & 3;    // slow turn
+           }
+
+           if (is_space_dir(cave, x, y, creature_move[dirn]))
+             move(cave, x, y, creature_move[dirn], base + dirn);    // turn and move to preferred dir
+           else if (is_space_dir(cave, x, y, creature_move[dir]))
+             move(cave, x, y, creature_move[dir], base + dir);    // go on
+           else
+             store(cave, x, y, base + dirp);    // turn in place if nothing else possible
+         }
+         break;
+
+       case O_WAITING_STONE:
+         if (is_space_dir(cave, x, y, grav_compat))
+         {
+           // beginning to fall
+           // it wakes up.
+           move(cave, x, y, grav_compat, O_CHASING_STONE);
+         }
+         else if (sloped_dir(cave, x, y, grav_compat, opposite[grav_compat]))
+         {
+           // rolling down a brick wall or a stone
+           if (sloped_dir(cave, x, y, grav_compat, cw_fourth[grav_compat]) &&
+               is_space_dir(cave, x, y, cw_fourth[grav_compat]) &&
+               is_space_dir(cave, x, y, cw_eighth[grav_compat]))
+           {
+             // maybe rolling left - see case O_STONE to understand why we use cw_fourth here
+             move(cave, x, y, cw_fourth[grav_compat], O_WAITING_STONE);
+           }
+           else if (sloped_dir(cave, x, y, grav_compat, ccw_fourth[grav_compat]) &&
+                    is_space_dir(cave, x, y, ccw_fourth[grav_compat]) &&
+                    is_space_dir(cave, x, y, ccw_eighth[grav_compat]))
+           {
+             // or maybe right
+             move(cave, x, y, ccw_fourth[grav_compat], O_WAITING_STONE);
+           }
+         }
+         break;
+
+       case O_CHASING_STONE:
+         {
+           int px = cave->px[0];
+           int py = cave->py[0];
+           boolean horizontal = gd_rand_boolean(cave->random);
+           boolean dont_move = FALSE;
+           int i = 3;
+
+           // try to move...
+           while (1)
+           {
+             if (horizontal)
+             {
+               // ------------------------------------------------------------
+               // check for a horizontal movement
+               // ------------------------------------------------------------
+               if (px == x)
+               {
+                 // if coordinates are the same
+                 i -= 1;
+                 horizontal = !horizontal;
+
+                 if (i == 2)
+                   continue;
+               }
+               else
+               {
+                 if (px > x && is_space_dir(cave, x, y, GD_MV_RIGHT))
+                 {
+                   move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
+                   dont_move = TRUE;
+                   break;
+                 }
+                 else if (px < x && is_space_dir(cave, x, y, GD_MV_LEFT))
+                 {
+                   move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
+                   dont_move = TRUE;
+                   break;
+                 }
+                 else
+                 {
+                   i -= 2;
+                   if (i == 1)
+                   {
+                     horizontal = !horizontal;
+                     continue;
+                   }
+                 }
+               }
+             }
+             else
+             {
+               // ------------------------------------------------------------
+               // check for a vertical movement
+               // ------------------------------------------------------------
+               if (py == y)
+               {
+                 // if coordinates are the same
+                 i -= 1;
+                 horizontal = !horizontal;
+                 if (i == 2)
+                   continue;
+               }
+               else
+               {
+                 if (py > y && is_space_dir(cave, x, y, GD_MV_DOWN))
+                 {
+                   move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
+                   dont_move = TRUE;
+                   break;
+                 }
+                 else if (py < y && is_space_dir(cave, x, y, GD_MV_UP))
+                 {
+                   move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
+                   dont_move = TRUE;
+                   break;
+                 }
+                 else
+                 {
+                   i -= 2;
+                   if (i == 1)
+                   {
+                     horizontal = !horizontal;
+                     continue;
+                   }
+                 }
+               }
+             }
+
+             if (i != 0)
+               dont_move = TRUE;
+
+             break;
+           }
+
+           // if we should move in both directions, but can not move in any, stop.
+           if (!dont_move)
+           {
+             if (horizontal)
+             {
+               // check for horizontal
+               if (x >= px)
+               {
+                 if (is_space_dir(cave, x, y, GD_MV_UP) &&
+                     is_space_dir(cave, x, y, GD_MV_UP_LEFT))
+                   move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
+                 else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
+                          is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
+                   move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
+               }
+               else
+               {
+                 if (is_space_dir(cave, x, y, GD_MV_UP) &&
+                     is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
+                   move(cave, x, y, GD_MV_UP, O_CHASING_STONE);
+                 else if (is_space_dir(cave, x, y, GD_MV_DOWN) &&
+                          is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
+                   move(cave, x, y, GD_MV_DOWN, O_CHASING_STONE);
+               }
+             }
+             else
+             {
+               // check for vertical
+               if (y >= py)
+               {
+                 if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
+                     is_space_dir(cave, x, y, GD_MV_UP_LEFT))
+                   move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
+                 else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
+                          is_space_dir(cave, x, y, GD_MV_UP_RIGHT))
+                   move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
+               }
+               else
+               {
+                 if (is_space_dir(cave, x, y, GD_MV_LEFT) &&
+                     is_space_dir(cave, x, y, GD_MV_DOWN_LEFT))
+                   move(cave, x, y, GD_MV_LEFT, O_CHASING_STONE);
+                 else if (is_space_dir(cave, x, y, GD_MV_RIGHT) &&
+                          is_space_dir(cave, x, y, GD_MV_DOWN_RIGHT))
+                   move(cave, x, y, GD_MV_RIGHT, O_CHASING_STONE);
+               }
+             }
+           }
+         }
+         break;
+
+       case O_REPLICATOR:
+         if (cave->replicators_wait_frame == 0 &&
+             cave->replicators_active &&
+             !cave->gravity_disabled)
+         {
+           // only replicate, if space is under it.
+           // do not replicate players!
+           // also obeys gravity settings.
+           // only replicate element if it is not a scanned one
+           // do not replicate space... that condition looks like it
+           // makes no sense, but otherwise it generates SCANNED spaces,
+           // which cannot be "collected" by the player, so he cannot run
+           // under a replicator
+           if (is_space_dir(cave, x, y, cave->gravity) &&
+               !is_player_dir(cave, x, y, opposite[cave->gravity]) &&
+               !is_space_dir(cave, x, y, opposite[cave->gravity]))
+           {
+             store_dir(cave, x, y, cave->gravity, get_dir(cave, x, y, opposite[cave->gravity]));
+             gd_sound_play(cave, GD_S_REPLICATOR, O_REPLICATOR, x, y);
+           }
+         }
+         break;
+
+       case O_BITER_1:
+       case O_BITER_2:
+       case O_BITER_3:
+       case O_BITER_4:
+         if (cave->biters_wait_frame == 0)
+         {
+           static GdDirection biter_move[] =
+           {
+             GD_MV_UP,
+             GD_MV_RIGHT,
+             GD_MV_DOWN,
+             GD_MV_LEFT
+           };
+
+           // direction, last two bits 0..3
+           int dir = get(cave, x, y) - O_BITER_1;
+           int dirn = (dir + 3) & 3;
+           int dirp = (dir + 1) & 3;
+           int i;
+           GdElement made_sound_of = O_NONE;
+
+           for (i = 0; i < ARRAY_SIZE (biter_try); i++)
+           {
+             if (is_element_dir(cave, x, y, biter_move[dir], biter_try[i]))
+             {
+               move(cave, x, y, biter_move[dir], O_BITER_1 + dir);
+               if (biter_try[i] != O_SPACE)
+                 made_sound_of = O_BITER_1;    // sound of a biter eating
+               break;
+             }
+             else if (is_element_dir(cave, x, y, biter_move[dirn], biter_try[i]))
+             {
+               move(cave, x, y, biter_move[dirn], O_BITER_1 + dirn);
+               if (biter_try[i] != O_SPACE)
+                 made_sound_of = O_BITER_1;    // sound of a biter eating
+               break;
+             }
+             else if (is_element_dir(cave, x, y, biter_move[dirp], biter_try[i]))
+             {
+               move(cave, x, y, biter_move[dirp], O_BITER_1 + dirp);
+               if (biter_try[i] != O_SPACE)
+                 made_sound_of = O_BITER_1;    // sound of a biter eating
+               break;
+             }
+           }
+
+           if (i == ARRAY_SIZE(biter_try))
+             // i = number of elements in array: could not move, so just turn
+             store(cave, x, y, O_BITER_1 + dirp);
+           else if (biter_try[i] == O_STONE)
+           {
+             // if there was a stone there, where we moved...
+             // do not eat stones, just throw them back
+             store(cave, x, y, O_STONE);
+             made_sound_of = O_STONE;
+           }
+
+           // if biter did move, we had sound. play it.
+           if (made_sound_of != O_NONE)
+             play_sound_of_element(cave, made_sound_of, x, y);
+         }
+         break;
+
+       case O_DRAGONFLY_1:
+       case O_DRAGONFLY_2:
+       case O_DRAGONFLY_3:
+       case O_DRAGONFLY_4:
+         // check if touches a voodoo
+         if (get_dir(cave, x, y, GD_MV_LEFT)  == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_RIGHT) == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_UP)    == O_VOODOO ||
+             get_dir(cave, x, y, GD_MV_DOWN)  == O_VOODOO)
+           cave->voodoo_touched = TRUE;
+
+         // check if touches something bad and should explode (includes voodoo by the flags)
+         if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
+           explode (cave, x, y);
+         // otherwise move
+         else
+         {
+           const GdDirection *creature_move;
+           boolean ccw = rotates_ccw(cave, x, y);    // check if default is counterclockwise
+           GdElement base = O_DRAGONFLY_1;    // base element number (which is like O_***_1)
+           int dir, dirn;    // direction
+
+           dir = get(cave, x, y)-base;    // facing where
+           creature_move = cave->creatures_backwards ? creature_chdir : creature_dir;
+
+           // now change direction if backwards
+           if (cave->creatures_backwards)
+             ccw = !ccw;
+
+           if (ccw)
+             dirn = (dir + 3) & 3;    // fast turn
+           else
+             dirn = (dir + 1) & 3;    // fast turn
+
+           // if can move forward, does so.
+           if (is_space_dir(cave, x, y, creature_move[dir]))
+             move(cave, x, y, creature_move[dir], base + dir);
+           else
+             // otherwise turns 90 degrees in place.
+             store(cave, x, y, base + dirn);
+         }
+         break;
+
+       case O_BLADDER:
+         store(cave, x, y, O_BLADDER_1);
+         break;
+
+       case O_BLADDER_1:
+       case O_BLADDER_2:
+       case O_BLADDER_3:
+       case O_BLADDER_4:
+       case O_BLADDER_5:
+       case O_BLADDER_6:
+       case O_BLADDER_7:
+       case O_BLADDER_8:
+         // bladder with any delay state: try to convert to clock.
+         if (is_element_dir(cave, x, y, opposite[grav_compat], cave->bladder_converts_by) ||
+             is_element_dir(cave, x, y, cw_fourth[grav_compat], cave->bladder_converts_by) || is_element_dir(cave, x, y, ccw_fourth[grav_compat], cave->bladder_converts_by))
+         {
+           // if touches the specified element, let it be a clock
+           store(cave, x, y, O_PRE_CLOCK_1);
+
+           // plays the bladder convert sound
+           play_sound_of_element(cave, O_PRE_CLOCK_1, x, y);
+         }
+         else
+         {
+           // is space over the bladder?
+           if (is_space_dir(cave, x, y, opposite[grav_compat]))
+           {
+             if (get(cave, x, y) == O_BLADDER_8)
+             {
+               // if it is a bladder 8, really move up
+               move(cave, x, y, opposite[grav_compat], O_BLADDER_1);
+               play_sound_of_element(cave, O_BLADDER, x, y);
+             }
+             else
+               // if smaller delay, just increase delay.
+               next(cave, x, y);
+           }
+           else
+             // if not space, is something sloped over the bladder?
+             if (sloped_for_bladder_dir(cave, x, y, opposite[grav_compat]) &&
+                 sloped_dir(cave, x, y, opposite[grav_compat], opposite[grav_compat]))
+             {
+               if (sloped_dir(cave, x, y, opposite[grav_compat], ccw_fourth[opposite[grav_compat]]) &&
+                   is_space_dir(cave, x, y, ccw_fourth[opposite[grav_compat]]) &&
+                   is_space_dir(cave, x, y, ccw_eighth[opposite[grav_compat]]))
+               {
+                 // rolling up, to left
+                 if (get(cave, x, y) == O_BLADDER_8)
+                 {
+                   // if it is a bladder 8, really roll
+                   move(cave, x, y, ccw_fourth[opposite[grav_compat]], O_BLADDER_8);
+                   play_sound_of_element(cave, O_BLADDER, x, y);
+                 }
+                 else
+                   // if smaller delay, just increase delay.
+                   next(cave, x, y);
+               }
+               else if (sloped_dir(cave, x, y, opposite[grav_compat], cw_fourth[opposite[grav_compat]]) &&
+                        is_space_dir(cave, x, y, cw_fourth[opposite[grav_compat]]) &&
+                        is_space_dir(cave, x, y, cw_eighth[opposite[grav_compat]]))
+               {
+                 // rolling up, to left
+                 if (get(cave, x, y) == O_BLADDER_8)
+                 {
+                   // if it is a bladder 8, really roll
+                   move(cave, x, y, cw_fourth[opposite[grav_compat]], O_BLADDER_8);
+                   play_sound_of_element(cave, O_BLADDER, x, y);
+                 }
+                 else
+                   // if smaller delay, just increase delay.
+                   next(cave, x, y);
+               }
+             }
+
+           // no space, no sloped thing over it - store bladder 1 and that is for now.
+             else
+               store(cave, x, y, O_BLADDER_1);
+         }
+         break;
+
+       case O_GHOST:
+         if (blows_up_flies_dir(cave, x, y, GD_MV_DOWN) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_UP) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_LEFT) ||
+             blows_up_flies_dir(cave, x, y, GD_MV_RIGHT))
+           explode (cave, x, y);
+         else
+         {
+           int i;
+
+           // the ghost is given four possibilities to move.
+           for (i = 0; i < 4; i++)
+           {
+             static GdDirection dirs[] =
+             {
+               GD_MV_UP,
+               GD_MV_DOWN,
+               GD_MV_LEFT,
+               GD_MV_RIGHT
+             };
+             GdDirection random_dir;
+
+             random_dir = dirs[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(dirs))];
+             if (is_space_dir(cave, x, y, random_dir))
+             {
+               move(cave, x, y, random_dir, O_GHOST);
+               break;    // ghost did move -> exit loop
+             }
+           }
+         }
+         break;
+
+         // ============================================================================
+         //    A C T I V E    E L E M E N T S
+         // ============================================================================
+
+       case O_AMOEBA:
+         // emulating BD1 amoeba+magic wall bug
+         if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
+         {
+           store(cave, x, y, cave->amoeba_enclosed_effect);
+           break;
+         }
+
+         amoeba_count++;
+         switch (cave->amoeba_state)
+         {
+           case GD_AM_TOO_BIG:
+             store(cave, x, y, cave->amoeba_too_big_effect);
+             break;
+
+           case GD_AM_ENCLOSED:
+             store(cave, x, y, cave->amoeba_enclosed_effect);
+             break;
+
+           case GD_AM_SLEEPING:
+           case GD_AM_AWAKE:
+             // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
+             if (amoeba_found_enclosed)
+               // if still found enclosed, check all four directions, if this one is able to grow.
+               if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
+                   amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
+                   amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
+                   amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
+               {
+                 // not enclosed. this is a local (per scan) flag!
+                 amoeba_found_enclosed = FALSE;
+                 cave->amoeba_state = GD_AM_AWAKE;
+               }
+
+             // if alive, check in which dir to grow (or not)
+             if (cave->amoeba_state == GD_AM_AWAKE)
+             {
+               if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_growth_prob)
+               {
+                 switch (gd_rand_int_range(cave->random, 0, 4))
+                 {
+                   // decided to grow, choose a random direction.
+                   case 0:    // let this be up. numbers indifferent.
+                     if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
+                       store_dir(cave, x, y, GD_MV_UP, O_AMOEBA);
+                     break;
+
+                   case 1:    // down
+                     if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
+                       store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA);
+                     break;
+
+                   case 2:    // left
+                     if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
+                       store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA);
+                     break;
+
+                   case 3:    // right
+                     if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
+                       store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA);
+                     break;
+                 }
+               }
+             }
+             break;
+
+         }
+         break;
+
+       case O_AMOEBA_2:
+         amoeba_2_count++;
+         // check if it is touching an amoeba, and explosion is enabled
+         if (cave->amoeba_2_explodes_by_amoeba &&
+             (is_element_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA) ||
+              is_element_dir(cave, x, y, GD_MV_UP, O_AMOEBA) ||
+              is_element_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA) ||
+              is_element_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA)))
+           explode (cave, x, y);
+         else
+           switch (cave->amoeba_2_state)
+           {
+             case GD_AM_TOO_BIG:
+               store(cave, x, y, cave->amoeba_2_too_big_effect);
+               break;
+
+             case GD_AM_ENCLOSED:
+               store(cave, x, y, cave->amoeba_2_enclosed_effect);
+               break;
+
+             case GD_AM_SLEEPING:
+             case GD_AM_AWAKE:
+               // if no amoeba found during THIS SCAN yet, which was able to grow, check this one.
+               if (amoeba_2_found_enclosed)
+                 if (amoeba_eats_dir(cave, x, y, GD_MV_UP) ||
+                     amoeba_eats_dir(cave, x, y, GD_MV_DOWN) ||
+                     amoeba_eats_dir(cave, x, y, GD_MV_LEFT) ||
+                     amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
+                 {
+                   // not enclosed. this is a local (per scan) flag!
+                   amoeba_2_found_enclosed = FALSE;
+                   cave->amoeba_2_state = GD_AM_AWAKE;
+                 }
+
+               // if it is alive, decide if it attempts to grow
+               if (cave->amoeba_2_state == GD_AM_AWAKE)
+                 if (gd_rand_int_range(cave->random, 0, 1000000) < cave->amoeba_2_growth_prob)
+                 {
+                   switch (gd_rand_int_range(cave->random, 0, 4))
+                   {
+                     // decided to grow, choose a random direction.
+                     case 0:    // let this be up. numbers indifferent.
+                       if (amoeba_eats_dir(cave, x, y, GD_MV_UP))
+                         store_dir(cave, x, y, GD_MV_UP, O_AMOEBA_2);
+                       break;
+
+                     case 1:    // down
+                       if (amoeba_eats_dir(cave, x, y, GD_MV_DOWN))
+                         store_dir(cave, x, y, GD_MV_DOWN, O_AMOEBA_2);
+                       break;
+
+                     case 2:    // left
+                       if (amoeba_eats_dir(cave, x, y, GD_MV_LEFT))
+                         store_dir(cave, x, y, GD_MV_LEFT, O_AMOEBA_2);
+                       break;
+
+                     case 3:    // right
+                       if (amoeba_eats_dir(cave, x, y, GD_MV_RIGHT))
+                         store_dir(cave, x, y, GD_MV_RIGHT, O_AMOEBA_2);
+                       break;
+                   }
+                 }
+               break;
+
+           }
+         break;
+
+       case O_ACID:
+         // choose randomly, if it spreads
+         if (gd_rand_int_range(cave->random, 0, 1000000) <= cave->acid_spread_ratio)
+         {
+           // the current one explodes
+           store(cave, x, y, cave->acid_turns_to);
+
+           // and if neighbours are eaten, put acid there.
+           if (is_element_dir(cave, x, y, GD_MV_UP, cave->acid_eats_this))
+           {
+             play_sound_of_element(cave, O_ACID, x, y);
+             store_dir(cave, x, y, GD_MV_UP, O_ACID);
+           }
+
+           if (is_element_dir(cave, x, y, GD_MV_DOWN, cave->acid_eats_this))
+           {
+             play_sound_of_element(cave, O_ACID, x, y);
+             store_dir(cave, x, y, GD_MV_DOWN, O_ACID);
+           }
+
+           if (is_element_dir(cave, x, y, GD_MV_LEFT, cave->acid_eats_this))
+           {
+             play_sound_of_element(cave, O_ACID, x, y);
+             store_dir(cave, x, y, GD_MV_LEFT, O_ACID);
+           }
+
+           if (is_element_dir(cave, x, y, GD_MV_RIGHT, cave->acid_eats_this))
+           {
+             play_sound_of_element(cave, O_ACID, x, y);
+             store_dir(cave, x, y, GD_MV_RIGHT, O_ACID);
+           }
+         }
+         break;
+
+       case O_WATER:
+         found_water = TRUE;
+         if (!cave->water_does_not_flow_down &&
+             is_space_dir(cave, x, y, GD_MV_DOWN))
+           // emulating the odd behaviour in crdr
+           store_dir(cave, x, y, GD_MV_DOWN, O_WATER_1);
+
+         if (is_space_dir(cave, x, y, GD_MV_UP))
+           store_dir(cave, x, y, GD_MV_UP, O_WATER_1);
+
+         if (is_space_dir(cave, x, y, GD_MV_LEFT))
+           store_dir(cave, x, y, GD_MV_LEFT, O_WATER_1);
+
+         if (is_space_dir(cave, x, y, GD_MV_RIGHT))
+           store_dir(cave, x, y, GD_MV_RIGHT, O_WATER_1);
+         break;
+
+       case O_WATER_16:
+         store(cave, x, y, O_WATER);
+         break;
+
+       case O_H_EXPANDING_WALL:
+       case O_V_EXPANDING_WALL:
+       case O_H_EXPANDING_STEEL_WALL:
+       case O_V_EXPANDING_STEEL_WALL:
+         // checks first if direction is changed.
+         if (((get(cave, x, y) == O_H_EXPANDING_WALL ||
+               get(cave, x, y) == O_H_EXPANDING_STEEL_WALL) &&
+              !cave->expanding_wall_changed) ||
+             ((get(cave, x, y) == O_V_EXPANDING_WALL ||
+               get(cave, x, y) == O_V_EXPANDING_STEEL_WALL) &&
+              cave->expanding_wall_changed))
+         {
+           if (is_space_dir(cave, x, y, GD_MV_LEFT))
+           {
+             store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
+             play_sound_of_element(cave, get(cave, x, y), x, y);
+           }
+
+           if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
+             store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
+             play_sound_of_element(cave, get(cave, x, y), x, y);
+           }
+         }
+         else
+         {
+           if (is_space_dir(cave, x, y, GD_MV_UP)) {
+             store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
+             play_sound_of_element(cave, get(cave, x, y), x, y);
+           }
+
+           if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
+             store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
+             play_sound_of_element(cave, get(cave, x, y), x, y);
+           }
+         }
+         break;
+
+       case O_EXPANDING_WALL:
+       case O_EXPANDING_STEEL_WALL:
+         // the wall which grows in all four directions.
+         if (is_space_dir(cave, x, y, GD_MV_LEFT))
+         {
+           store_dir(cave, x, y, GD_MV_LEFT, get(cave, x, y));
+           play_sound_of_element(cave, get(cave, x, y), x, y);
+         }
+
+         if (is_space_dir(cave, x, y, GD_MV_RIGHT)) {
+           store_dir(cave, x, y, GD_MV_RIGHT, get(cave, x, y));
+           play_sound_of_element(cave, get(cave, x, y), x, y);
+         }
+
+         if (is_space_dir(cave, x, y, GD_MV_UP)) {
+           store_dir(cave, x, y, GD_MV_UP, get(cave, x, y));
+           play_sound_of_element(cave, get(cave, x, y), x, y);
+         }
+
+         if (is_space_dir(cave, x, y, GD_MV_DOWN)) {
+           store_dir(cave, x, y, GD_MV_DOWN, get(cave, x, y));
+           play_sound_of_element(cave, get(cave, x, y), x, y);
+         }
+         break;
+
+       case O_SLIME:
+#if 1
+         ; // to make compilers happy ...
+#else
+         Info("Step[%03d]", cave->frame); // XXX
+#endif
+         int rrr = gd_cave_c64_random(cave);
+#if 1
+#else
+         Info(".Rand[%03d].Perm[%03d].Result[%d]\n", rrr, cave->slime_permeability_c64,
+              (rrr & cave->slime_permeability_c64) == 0);
+#endif
+         /*
+          * unpredictable: gd_rand_int
+          * predictable: c64 predictable random generator.
+          *    for predictable, a random number is generated,
+          *    whether or not it is even possible that the stone will be able to pass.
+          */
+         if (cave->slime_predictable ? ((rrr /* XXX */ & cave->slime_permeability_c64) == 0) : gd_rand_int_range(cave->random, 0, 1000000) < cave->slime_permeability)
+         {
+           GdDirection grav = cave->gravity;
+           GdDirection oppos = opposite[cave->gravity];
+
+           // space under the slime? elements may pass from top to bottom then.
+           if (is_space_dir(cave, x, y, grav))
+           {
+             if (get_dir(cave, x, y, oppos) == cave->slime_eats_1)
+             {
+               // output a falling xy under
+               store_dir(cave, x, y, grav, cave->slime_converts_1);
+
+               store_dir(cave, x, y, oppos, O_SPACE);
+               play_sound_of_element(cave, O_SLIME, x, y);
+             }
+             else if (get_dir(cave, x, y, oppos) == cave->slime_eats_2)
+             {
+               store_dir(cave, x, y, grav, cave->slime_converts_2);
+               store_dir(cave, x, y, oppos, O_SPACE);
+               play_sound_of_element(cave, O_SLIME, x, y);
+             }
+             else if (get_dir(cave, x, y, oppos) == cave->slime_eats_3)
+             {
+               store_dir(cave, x, y, grav, cave->slime_converts_3);
+               store_dir(cave, x, y, oppos, O_SPACE);
+               play_sound_of_element(cave, O_SLIME, x, y);
+             }
+             else if (get_dir(cave, x, y, oppos) == O_WAITING_STONE)
+             {
+               // waiting stones pass without awakening
+               store_dir(cave, x, y, grav, O_WAITING_STONE);
+               store_dir(cave, x, y, oppos, O_SPACE);
+               play_sound_of_element(cave, O_SLIME, x, y);
+             }
+             else if (get_dir(cave, x, y, oppos) == O_CHASING_STONE)
+             {
+               // chasing stones pass
+               store_dir(cave, x, y, grav, O_CHASING_STONE);
+               store_dir(cave, x, y, oppos, O_SPACE);
+               play_sound_of_element(cave, O_SLIME, x, y);
+             }
+           }
+           else
+           {
+             // or space over the slime? elements may pass from bottom to up then.
+             if (is_space_dir(cave, x, y, oppos))
+             {
+               if (get_dir(cave, x, y, grav) == O_BLADDER)
+               {
+                 // bladders move UP the slime
+                 store_dir(cave, x, y, grav, O_SPACE);
+                 store_dir(cave, x, y, oppos, O_BLADDER_1);
+                 play_sound_of_element(cave, O_SLIME, x, y);
+               }
+               else if (get_dir(cave, x, y, grav) == O_FLYING_STONE)
+               {
+                 store_dir(cave, x, y, grav, O_SPACE);
+                 store_dir(cave, x, y, oppos, O_FLYING_STONE_F);
+                 play_sound_of_element(cave, O_SLIME, x, y);
+               }
+               else if (get_dir(cave, x, y, grav) == O_FLYING_DIAMOND)
+               {
+                 store_dir(cave, x, y, grav, O_SPACE);
+                 store_dir(cave, x, y, oppos, O_FLYING_DIAMOND_F);
+                 play_sound_of_element(cave, O_SLIME, x, y);
+               }
+             }
+           }
+         }
+         break;
+
+       case O_FALLING_WALL:
+         if (is_space_dir(cave, x, y, grav_compat))
+         {
+           // try falling if space under.
+           int yy;
+
+           for (yy = y + 1; yy < y + cave->h; yy++)
+             // yy < y + cave->h is to check everything OVER the wall - since caves wrap around !!
+             if (get(cave, x, yy) != O_SPACE)
+               // stop cycle when other than space
+               break;
+
+           // if scanning stopped by a player... start falling!
+           if (get(cave, x, yy) == O_PLAYER ||
+               get(cave, x, yy) == O_PLAYER_GLUED ||
+               get(cave, x, yy) == O_PLAYER_BOMB)
+           {
+             move(cave, x, y, grav_compat, O_FALLING_WALL_F);
+             // no sound when the falling wall starts falling!
+           }
+         }
+         break;
+
+       case O_FALLING_WALL_F:
+         switch (get_dir(cave, x, y, grav_compat))
+         {
+           case O_PLAYER:
+           case O_PLAYER_GLUED:
+           case O_PLAYER_BOMB:
+             // if player under, it explodes - the falling wall, not the player!
+             explode(cave, x, y);
+             break;
+
+           case O_SPACE:
+             // continue falling
+             move(cave, x, y, grav_compat, O_FALLING_WALL_F);
+             break;
+
+           default:
+             // stop
+             play_sound_of_element(cave, get(cave, x, y), x, y);
+             store(cave, x, y, O_FALLING_WALL);
+             break;
+         }
+         break;
+
+         // ============================================================================
+         //    C O N V E Y O R    B E L T S
+         // ============================================================================
+
+       case O_CONVEYOR_RIGHT:
+       case O_CONVEYOR_LEFT:
+         // only works if gravity is up or down!!!
+         // first, check for gravity and running belts.
+         if (!cave->gravity_disabled && cave->conveyor_belts_active)
+         {
+           const GdDirection *dir;
+           boolean left;
+
+           // decide direction
+           left = get(cave, x, y) != O_CONVEYOR_RIGHT;
+           if (cave->conveyor_belts_direction_changed)
+             left = !left;
+           dir = left ? ccw_eighth : cw_eighth;
+
+           // CHECK IF IT CONVEYS THE ELEMENT ABOVE IT
+           // if gravity is normal, and the conveyor belt has something
+           // ABOVE which can be moved
+           // OR
+           // the gravity is up, so anything that should float now goes
+           // DOWN and touches the conveyor
+           if ((cave->gravity == GD_MV_DOWN &&
+                moved_by_conveyor_top_dir(cave, x, y, GD_MV_UP)) ||
+               (cave->gravity == GD_MV_UP &&
+                moved_by_conveyor_bottom_dir(cave, x, y, 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.
+             }
+           }
+
+           // CHECK IF IT CONVEYS THE ELEMENT BELOW IT
+           if ((cave->gravity == GD_MV_UP &&
+                moved_by_conveyor_top_dir(cave, x, y, GD_MV_DOWN)) ||
+               (cave->gravity == GD_MV_DOWN &&
+                moved_by_conveyor_bottom_dir(cave, x, y, 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.
+             }
+           }
+         }
+         break;
+
+         // ============================================================================
+         //    R O C K E T S
+         // ============================================================================
+
+       case O_ROCKET_1:
+         if (is_space_dir(cave, x, y, GD_MV_RIGHT))
+           move(cave, x, y, GD_MV_RIGHT, O_ROCKET_1);
+         else
+           explode(cave, x, y);
+         break;
+
+       case O_ROCKET_2:
+         if (is_space_dir(cave, x, y, GD_MV_UP))
+           move(cave, x, y, GD_MV_UP, O_ROCKET_2);
+         else
+           explode(cave, x, y);
+         break;
+
+       case O_ROCKET_3:
+         if (is_space_dir(cave, x, y, GD_MV_LEFT))
+           move(cave, x, y, GD_MV_LEFT, O_ROCKET_3);
+         else
+           explode(cave, x, y);
+         break;
+
+       case O_ROCKET_4:
+         if (is_space_dir(cave, x, y, GD_MV_DOWN))
+           move(cave, x, y, GD_MV_DOWN, O_ROCKET_4);
+         else
+           explode(cave, x, y);
+         break;
+
+         // ============================================================================
+         //    S I M P L E   C H A N G I N G;   E X P L O S I O N S
+         // ============================================================================
+
+       case O_EXPLODE_5:
+         store(cave, x, y, cave->explosion_effect);
+         break;
+
+       case O_NUT_EXPL_4:
+         store(cave, x, y, O_DIAMOND);
+         break;
+
+       case O_PRE_DIA_5:
+         store(cave, x, y, cave->diamond_birth_effect);
+         break;
+
+       case O_PRE_STONE_4:
+         store(cave, x, y, O_STONE);
+         break;
+
+       case O_NITRO_EXPL_4:
+         store(cave, x, y, cave->nitro_explosion_effect);
+         break;
+
+       case O_BOMB_EXPL_4:
+         store(cave, x, y, cave->bomb_explosion_effect);
+         break;
+
+       case O_AMOEBA_2_EXPL_4:
+         store(cave, x, y, cave->amoeba_2_explosion_effect);
+         break;
+
+       case O_GHOST_EXPL_4:
+         {
+           static GdElement ghost_explode[] =
+           {
+             O_SPACE, O_SPACE, O_DIRT, O_DIRT, O_CLOCK, O_CLOCK, O_PRE_OUTBOX,
+             O_BOMB, O_BOMB, O_PLAYER, O_GHOST, O_BLADDER, O_DIAMOND, O_SWEET,
+             O_WAITING_STONE, O_BITER_1
+           };
+
+           store(cave, x, y, ghost_explode[gd_rand_int_range(cave->random, 0, ARRAY_SIZE(ghost_explode))]);
+         }
+         break;
+
+       case O_PRE_STEEL_4:
+         store(cave, x, y, O_STEEL);
+         break;
+
+       case O_PRE_CLOCK_4:
+         store(cave, x, y, O_CLOCK);
+         break;
+
+       case O_BOMB_TICK_7:
+         explode(cave, x, y);
+         break;
+
+       case O_TRAPPED_DIAMOND:
+         if (cave->diamond_key_collected)
+           store(cave, x, y, O_DIAMOND);
+         break;
+
+       case O_PRE_OUTBOX:
+         if (cave->gate_open) // if no more diamonds needed
+           store(cave, x, y, O_OUTBOX);    // open outbox
+         break;
+
+       case O_PRE_INVIS_OUTBOX:
+         if (cave->gate_open)    // if no more diamonds needed
+           store(cave, x, y, O_INVIS_OUTBOX);    // open outbox. invisible one :P
+         break;
+
+       case O_INBOX:
+         if (cave->hatched && !inbox_toggle)    // if it is time of birth
+           store(cave, x, y, O_PRE_PL_1);
+         inbox_toggle = !inbox_toggle;
+         break;
+
+       case O_PRE_PL_3:
+         store(cave, x, y, O_PLAYER);
+         break;
+
+       case O_PRE_DIA_1:
+       case O_PRE_DIA_2:
+       case O_PRE_DIA_3:
+       case O_PRE_DIA_4:
+       case O_PRE_STONE_1:
+       case O_PRE_STONE_2:
+       case O_PRE_STONE_3:
+       case O_BOMB_TICK_1:
+       case O_BOMB_TICK_2:
+       case O_BOMB_TICK_3:
+       case O_BOMB_TICK_4:
+       case O_BOMB_TICK_5:
+       case O_BOMB_TICK_6:
+       case O_PRE_STEEL_1:
+       case O_PRE_STEEL_2:
+       case O_PRE_STEEL_3:
+       case O_BOMB_EXPL_1:
+       case O_BOMB_EXPL_2:
+       case O_BOMB_EXPL_3:
+       case O_NUT_EXPL_1:
+       case O_NUT_EXPL_2:
+       case O_NUT_EXPL_3:
+       case O_GHOST_EXPL_1:
+       case O_GHOST_EXPL_2:
+       case O_GHOST_EXPL_3:
+       case O_EXPLODE_1:
+       case O_EXPLODE_2:
+       case O_EXPLODE_3:
+       case O_EXPLODE_4:
+       case O_PRE_PL_1:
+       case O_PRE_PL_2:
+       case O_PRE_CLOCK_1:
+       case O_PRE_CLOCK_2:
+       case O_PRE_CLOCK_3:
+       case O_NITRO_EXPL_1:
+       case O_NITRO_EXPL_2:
+       case O_NITRO_EXPL_3:
+       case O_AMOEBA_2_EXPL_1:
+       case O_AMOEBA_2_EXPL_2:
+       case O_AMOEBA_2_EXPL_3:
+         // simply the next identifier
+         next(cave, x, y);
+         break;
+
+       case O_WATER_1:
+       case O_WATER_2:
+       case O_WATER_3:
+       case O_WATER_4:
+       case O_WATER_5:
+       case O_WATER_6:
+       case O_WATER_7:
+       case O_WATER_8:
+       case O_WATER_9:
+       case O_WATER_10:
+       case O_WATER_11:
+       case O_WATER_12:
+       case O_WATER_13:
+       case O_WATER_14:
+       case O_WATER_15:
+         found_water = TRUE;    // for sound
+         // simply the next identifier
+         next(cave, x, y);
+         break;
+
+       case O_BLADDER_SPENDER:
+         if (is_space_dir(cave, x, y, opposite[grav_compat]))
+         {
+           store_dir(cave, x, y, opposite[grav_compat], O_BLADDER);
+           store(cave, x, y, O_PRE_STEEL_1);
+           play_sound_of_element(cave, O_BLADDER_SPENDER, x, y);
+         }
+         break;
+
+       default:
+         // other inanimate elements that do nothing
+         break;
+      }
+    }
+  }
+
+
+  // ============================================================================
+  // POSTPROCESSING
+  // ============================================================================
+
+  // another scan-like routine:
+  // short explosions (for example, in bd1) started with explode_2.
+  // internally we use explode_1; and change it to explode_2 if needed.
+  if (cave->short_explosions)
+  {
+    for (y = 0; y < cave->h; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       if (is_first_stage_of_explosion(cave, x, y))
+       {
+         next(cave, x, y);    // select next frame of explosion
+
+         // forget scanned flag immediately
+         store(cave, x, y, get(cave, x, y) & ~SCANNED);
+       }
+      }
+    }
+  }
+
+  // finally: forget "scanned" flags for objects.
+  // also, check for time penalties.
+  // these is something like an effect table, but we do not really use one.
+  for (y = 0; y < cave->h; y++)
+  {
+    for (x = 0; x < cave->w; x++)
+    {
+      if (get(cave, x, y) & SCANNED)
+       store(cave, x, y, get(cave, x, y) & ~SCANNED);
+
+      if (get(cave, x, y) == O_TIME_PENALTY)
+      {
+       store(cave, x, y, O_GRAVESTONE);
+
+       // there is time penalty for destroying the voodoo
+       time_decrement_sec += cave->time_penalty;
+      }
+    }
+  }
+
+  // this loop finds the coordinates of the player. needed for scrolling and chasing stone.
+  // but we only do this, if a living player was found. if not yet, the setup
+  // routine coordinates are used
+  if (cave->player_state == GD_PL_LIVING)
+  {
+    if (cave->active_is_first_found)
+    {
+      // to be 1stb compatible, we do everything backwards.
+      for (y = cave->h - 1; y >= 0; y--)
+      {
+       for (x = cave->w - 1; x >= 0; x--)
+       {
+         if (is_player(cave, x, y))
+         {
+           // here we remember the coordinates.
+           cave->player_x = x;
+           cave->player_y = y;
+         }
+       }
+      }
+    }
+    else
+    {
+      // as in the original: look for the last one
+      for (y = 0; y < cave->h; y++)
+      {
+       for (x = 0; x < cave->w; x++)
+       {
+         if (is_player(cave, x, y))
+         {
+           // here we remember the coordinates.
+           cave->player_x = x;
+           cave->player_y = y;
+         }
+       }
+      }
+    }
+  }
+
+  // record coordinates of player for chasing stone
+  for (i = 0; i < ARRAY_SIZE(cave->px) - 1; i++)
+  {
+    cave->px[i] = cave->px[i + 1];
+    cave->py[i] = cave->py[i + 1];
+  }
+
+  cave->px[ARRAY_SIZE(cave->px) - 1] = cave->player_x;
+  cave->py[ARRAY_SIZE(cave->py) - 1] = cave->player_y;
+
+  // SCHEDULING
+
+  // update timing calculated by iterating and counting elements
+  update_cave_speed(cave);
+
+  // cave 3 sounds. precedence is controlled by the sound_play function.
+  // but we have to check amoeba&magic together as they had a different gritty sound when mixed
+  if (found_water)
+    gd_sound_play(cave, GD_S_WATER, O_WATER, -1, -1);
+
+  magic_sound = (cave->magic_wall_state == GD_MW_ACTIVE &&
+                cave->magic_wall_sound);
+
+  amoeba_sound = (cave->hatched && cave->amoeba_sound &&
+                 ((amoeba_count > 0 && cave->amoeba_state == GD_AM_AWAKE) ||
+                  (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE)));
+
+  if (amoeba_sound && magic_sound)
+  {
+    gd_sound_play(cave, GD_S_AMOEBA_MAGIC, O_AMOEBA, -1, -1);
+  }
+  else
+  {
+    if (amoeba_sound)
+      gd_sound_play(cave, GD_S_AMOEBA, O_AMOEBA, -1, -1);
+    else if (magic_sound)
+      gd_sound_play(cave, GD_S_MAGIC_WALL, O_MAGIC_WALL, -1, -1);
+  }
+
+  if (cave->hatched)
+  {
+    if ((amoeba_count   > 0 && cave->amoeba_state   == GD_AM_AWAKE) ||
+       (amoeba_2_count > 0 && cave->amoeba_2_state == GD_AM_AWAKE))
+      play_sound_of_element(cave, O_AMOEBA, -1, -1);
+  }
+
+  // pneumatic hammer sound - overrides everything.
+  if (cave->pneumatic_hammer_active_delay > 0)
+    gd_sound_play(cave, GD_S_PNEUMATIC_HAMMER, O_PNEUMATIC_HAMMER, -1, -1);
+
+
+  // ============================================================================
+  // CAVE VARIABLES
+  // ============================================================================
+
+  // PLAYER
+
+  // check if player is alive.
+  if ((cave->player_state == GD_PL_LIVING && cave->player_seen_ago > 1) || cave->kill_player)
+    cave->player_state = GD_PL_DIED;
+
+  // check if any voodoo exploded, and kill players the next scan if that happended.
+  if (cave->voodoo_touched)
+    cave->kill_player = TRUE;
+
+  // AMOEBA
+
+  // check flags after evaluating.
+  if (cave->amoeba_state == GD_AM_AWAKE)
+  {
+    if (amoeba_count >= cave->amoeba_max_count)
+      cave->amoeba_state = GD_AM_TOO_BIG;
+    if (amoeba_found_enclosed)
+      cave->amoeba_state = GD_AM_ENCLOSED;
+    }
+
+  // amoeba can also be turned into diamond by magic wall
+  if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
+    cave->amoeba_state = GD_AM_ENCLOSED;
+
+  // AMOEBA 2
+  if (cave->amoeba_2_state == GD_AM_AWAKE)
+  {
+    // check flags after evaluating.
+    if (amoeba_2_count >= cave->amoeba_2_max_count)
+      cave->amoeba_2_state = GD_AM_TOO_BIG;
+
+    if (amoeba_2_found_enclosed)
+      cave->amoeba_2_state = GD_AM_ENCLOSED;
+  }
+
+  // amoeba 2 can also be turned into diamond by magic wall
+  if (cave->magic_wall_stops_amoeba && cave->magic_wall_state == GD_MW_ACTIVE)
+    cave->amoeba_2_state = GD_AM_ENCLOSED;
+
+  // now check times. ---------------------------
+  // decrement time if a voodoo was killed.
+  cave->time -= time_decrement_sec * cave->timing_factor;
+  if (cave->time < 0)
+    cave->time = 0;
+
+  // only decrement time when player is already born.
+  if (cave->hatched)
+  {
+    int secondsbefore, secondsafter;
+
+    secondsbefore = cave->time / cave->timing_factor;
+    cave->time -= cave->speed;
+    if (cave->time <= 0)
+      cave->time = 0;
+
+    secondsafter = cave->time / cave->timing_factor;
+    if (cave->time / cave->timing_factor < 10)
+      // if less than 10 seconds, no walking sound, but play explosion sound
+      gd_sound_play(cave, GD_S_NONE, O_NONE, -1, -1);
+
+    if (secondsbefore != secondsafter)
+      gd_cave_set_seconds_sound(cave);
+  }
+
+  // a gravity switch was activated; seconds counting down
+  if (cave->gravity_will_change > 0)
+  {
+    cave->gravity_will_change -= cave->speed;
+    if (cave->gravity_will_change < 0)
+      cave->gravity_will_change = 0;
+
+    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
+    }
+  }
+
+  // creatures direction automatically change
+  if (cave->creatures_direction_will_change > 0)
+  {
+    cave->creatures_direction_will_change -= cave->speed;
+    if (cave->creatures_direction_will_change < 0)
+      cave->creatures_direction_will_change = 0;
+
+    if (cave->creatures_direction_will_change == 0)
+    {
+      gd_sound_play(cave, GD_S_SWITCH_CREATURES, O_CREATURE_SWITCH, -1, -1);
+
+      cave->creatures_backwards = !cave->creatures_backwards;
+      cave->creatures_direction_will_change =
+       cave->creatures_direction_auto_change_time * cave->timing_factor;
+    }
+  }
+
+  // magic wall; if active&wait or not wait for hatching
+  if (cave->magic_wall_state == GD_MW_ACTIVE &&
+      (cave->hatched || !cave->magic_timer_wait_for_hatching) &&
+      !(cave->magic_wall_time == 0 && cave->magic_timer_zero_is_infinite))
+  {
+    cave->magic_wall_time -= cave->speed;
+    if (cave->magic_wall_time < 0)
+      cave->magic_wall_time = 0;
+    if (cave->magic_wall_time == 0)
+      cave->magic_wall_state = GD_MW_EXPIRED;
+  }
+
+  // we may wait for hatching, when starting amoeba
+  if (cave->amoeba_timer_started_immediately ||
+      (cave->amoeba_state == GD_AM_AWAKE &&
+       (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
+  {
+    cave->amoeba_time -= cave->speed;
+    if (cave->amoeba_time < 0)
+      cave->amoeba_time = 0;
+    if (cave->amoeba_time == 0)
+      cave->amoeba_growth_prob = cave->amoeba_fast_growth_prob;
+  }
+
+  // we may wait for hatching, when starting amoeba
+  if (cave->amoeba_timer_started_immediately ||
+      (cave->amoeba_2_state == GD_AM_AWAKE &&
+       (cave->hatched || !cave->amoeba_timer_wait_for_hatching)))
+  {
+    cave->amoeba_2_time -= cave->speed;
+    if (cave->amoeba_2_time < 0)
+      cave->amoeba_2_time = 0;
+    if (cave->amoeba_2_time == 0)
+      cave->amoeba_2_growth_prob = cave->amoeba_2_fast_growth_prob;
+  }
+
+  // check for player hatching.
+  start_signal = FALSE;
+
+  // if not the c64 scheduling, but the correct frametime is used,
+  // hatching delay should always be decremented.
+  // otherwise, the if (millisecs...) condition below will set this.
+  if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
+  {
+    // NON-C64 scheduling
+    if (cave->hatching_delay_frame > 0)
+    {
+      // for milliseconds-based, non-c64 schedulings, hatching delay means frames.
+      cave->hatching_delay_frame--;
+      if (cave->hatching_delay_frame == 0)
+       start_signal = TRUE;
+    }
+  }
+  else
+  {
+    // C64 scheduling
+    if (cave->hatching_delay_time > 0)
+    {
+      // for c64 schedulings, hatching delay means milliseconds.
+      cave->hatching_delay_time -= cave->speed;
+      if (cave->hatching_delay_time <= 0)
+      {
+       cave->hatching_delay_time = 0;
+       start_signal = TRUE;
+      }
+    }
+  }
+
+  // if decremented hatching, and it became zero:
+  if (start_signal)
+  {
+    // THIS IS THE CAVE START SIGNAL
+
+    // record that now the cave is in its normal state
+    cave->hatched = TRUE;
+
+    // if diamonds needed is below zero, we count the available diamonds now.
+    gd_cave_count_diamonds(cave);
+
+    // setup direction auto change
+    if (cave->creatures_direction_auto_change_time)
+    {
+      cave->creatures_direction_will_change =
+       cave->creatures_direction_auto_change_time * cave->timing_factor;
+
+      if (cave->creatures_direction_auto_change_on_start)
+       cave->creatures_backwards = !cave->creatures_backwards;
+    }
+
+    gd_sound_play(cave, GD_S_CRACKING, O_INBOX, -1, -1);
+  }
+
+  // for biters
+  if (cave->biters_wait_frame == 0)
+    cave->biters_wait_frame = cave->biter_delay_frame;
+  else
+    cave->biters_wait_frame--;
+
+  // replicators delay
+  if (cave->replicators_wait_frame == 0)
+    cave->replicators_wait_frame = cave->replicator_delay_frame;
+  else
+    cave->replicators_wait_frame--;
+
+
+  // ============================================================================
+  // LAST THOUGTS
+  // ============================================================================
+
+#if 1
+  // check if cave failed by timeout is done in main game engine
+#else
+  // check if cave failed by timeout
+  if (cave->player_state == GD_PL_LIVING && cave->time == 0)
+  {
+    gd_cave_clear_sounds(cave);
+    cave->player_state = GD_PL_TIMEOUT;
+    gd_sound_play(cave, GD_S_TIMEOUT_0, O_NONE, -1, -1);
+  }
+#endif
+
+  // set these for drawing.
+  cave->last_direction = player_move;
+
+  // here we remember last movements for animation. this is needed here,
+  // as animation is in sync with the game, not the keyboard directly.
+  // (for example, after exiting the cave, the player was "running" in the
+  // original, till bonus points were counted for remaining time and so on.
+  if (player_move == GD_MV_LEFT ||
+      player_move == GD_MV_UP_LEFT ||
+      player_move == GD_MV_DOWN_LEFT)
+    cave->last_horizontal_direction = GD_MV_LEFT;
+
+  if (player_move == GD_MV_RIGHT ||
+      player_move == GD_MV_UP_RIGHT ||
+      player_move == GD_MV_DOWN_RIGHT)
+    cave->last_horizontal_direction = GD_MV_RIGHT;
+
+  cave->frame++;  // XXX
+}
+
+void set_initial_cave_speed(GdCave *cave)
+{
+  int ymin, ymax;
+  int x, y;
+
+  // set cave get function; to implement perfect or lineshifting borders
+  if (cave->lineshift)
+    cave->getp = getp_shift;
+  else
+    cave->getp = getp_perfect;
+
+  // check whether to scan the first and last line
+  if (cave->border_scan_first_and_last)
+  {
+    ymin = 0;
+    ymax = cave->h - 1;
+  }
+  else
+  {
+    ymin = 1;
+    ymax = cave->h - 2;
+  }
+
+  for (y = ymin; y <= ymax; y++)
+  {
+    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;
+    }
+  }
+
+  // update timing calculated by iterating and counting elements
+  update_cave_speed(cave);
+}
diff --git a/src/game_bd/bd_caveengine.h b/src/game_bd/bd_caveengine.h
new file mode 100644 (file)
index 0000000..b4c44f5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVEENGINE_H
+#define BD_CAVEENGINE_H
+
+#include "bd_cave.h"
+
+
+// the game itself
+boolean is_player(const GdCave *cave, const int x, const int y);
+boolean can_be_pushed_dir(const GdCave *cave, const int x, const int y, const GdDirection dir);
+GdDirection gd_direction_from_keypress(boolean up, boolean down, boolean left, boolean right);
+void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire, boolean suicide);
+void set_initial_cave_speed(GdCave *cave);
+void gd_cave_set_seconds_sound(GdCave *cave);
+void gd_cave_clear_sounds(GdCave *cave);
+
+#endif // BD_CAVEENGINE_H
diff --git a/src/game_bd/bd_caveobject.c b/src/game_bd/bd_caveobject.c
new file mode 100644 (file)
index 0000000..cea246f
--- /dev/null
@@ -0,0 +1,1578 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+GdObjectLevels gd_levels_mask[] =
+{
+  GD_OBJECT_LEVEL1,
+  GD_OBJECT_LEVEL2,
+  GD_OBJECT_LEVEL3,
+  GD_OBJECT_LEVEL4,
+  GD_OBJECT_LEVEL5
+};
+
+// bdcff text description of object. caller should free string.
+char *gd_object_get_bdcff(const GdObject *object)
+{
+  char *str = NULL;
+  int j;
+  const char *type;
+
+  switch (object->type)
+  {
+    case GD_POINT:
+      return getStringPrint("Point=%d %d %s", object->x1, object->y1, gd_elements[object->element].filename);
+
+    case GD_LINE:
+      return getStringPrint("Line=%d %d %d %d %s", object->x1, object->y1, object->x2, object->y2, gd_elements[object->element].filename);
+
+    case GD_RECTANGLE:
+      return getStringPrint("Rectangle=%d %d %d %d %s", object->x1, object->y1, object->x2, object->y2, gd_elements[object->element].filename);
+
+    case GD_FILLED_RECTANGLE:
+      // if elements are not the same
+      if (object->fill_element!=object->element)
+       return getStringPrint("FillRect=%d %d %d %d %s %s", object->x1, object->y1, object->x2, object->y2, gd_elements[object->element].filename, gd_elements[object->fill_element].filename);
+      // they are the same
+      return getStringPrint("FillRect=%d %d %d %d %s", object->x1, object->y1, object->x2, object->y2, gd_elements[object->element].filename);
+
+    case GD_RASTER:
+      return getStringPrint("Raster=%d %d %d %d %d %d %s", object->x1, object->y1, (object->x2-object->x1)/object->dx+1, (object->y2-object->y1)/object->dy+1, object->dx, object->dy, gd_elements[object->element].filename);
+
+    case GD_JOIN:
+      return getStringPrint("Add=%d %d %s %s", object->dx, object->dy, gd_elements[object->element].filename, gd_elements[object->fill_element].filename);
+
+    case GD_FLOODFILL_BORDER:
+      return getStringPrint("BoundaryFill=%d %d %s %s", object->x1, object->y1, gd_elements[object->fill_element].filename, gd_elements[object->element].filename);
+
+    case GD_FLOODFILL_REPLACE:
+      return getStringPrint("FloodFill=%d %d %s %s", object->x1, object->y1, gd_elements[object->fill_element].filename, gd_elements[object->element].filename);
+
+    case GD_MAZE:
+    case GD_MAZE_UNICURSAL:
+    case GD_MAZE_BRAID:
+      switch(object->type)
+      {
+       case GD_MAZE:
+         type = "perfect";
+         break;
+
+       case GD_MAZE_UNICURSAL:
+         type = "unicursal";
+         break;
+
+       case GD_MAZE_BRAID:
+         type = "braid";
+         break;
+
+       default:
+         // never reached
+         break;
+      }
+
+      return getStringPrint("Maze=%d %d %d %d %d %d %d %d %d %d %d %d %s %s %s", object->x1, object->y1, object->x2, object->y2, object->dx, object->dy, object->horiz, object->seed[0], object->seed[1], object->seed[2], object->seed[3], object->seed[4], gd_elements[object->element].filename, gd_elements[object->fill_element].filename, type);
+
+    case GD_RANDOM_FILL:
+      appendStringPrint(&str, "%s=%d %d %d %d %d %d %d %d %d %s", object->c64_random?"RandomFillC64":"RandomFill", object->x1, object->y1, object->x2, object->y2, object->seed[0], object->seed[1], object->seed[2], object->seed[3], object->seed[4], gd_elements[object->fill_element].filename);
+
+      // seed and initial fill
+      for (j = 0; j < 4; j++)
+       if (object->random_fill_probability[j] != 0)
+         appendStringPrint(&str, " %s %d", gd_elements[object->random_fill[j]].filename, object->random_fill_probability[j]);
+
+      if (object->element != O_NONE)
+       appendStringPrint(&str, " %s", gd_elements[object->element].filename);
+
+      return str;
+
+    case GD_COPY_PASTE:
+      return getStringPrint("CopyPaste=%d %d %d %d %d %d %s %s", object->x1, object->y1, object->x2, object->y2, object->dx, object->dy, object->mirror?"mirror":"nomirror", object->flip?"flip":"noflip");
+
+    case NONE:
+      // never reached
+      break;
+  }
+
+  return NULL;
+}
+
+// create an INDIVIDUAL POINT CAVE OBJECT
+GdObject *gd_object_new_point(GdObjectLevels levels, int x, int y, GdElement elem)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_POINT;
+  newobj->x1 = x;
+  newobj->y1 = y;
+  newobj->element = elem;
+
+  return newobj;
+}
+
+// create a LINE OBJECT
+GdObject *gd_object_new_line(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                            GdElement elem)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_LINE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->element = elem;
+
+  return newobj;
+}
+
+// create a RECTANGLE OBJECT
+GdObject *gd_object_new_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                 GdElement elem)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_RECTANGLE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->element = elem;
+
+  return newobj;
+}
+
+// create a RECTANGLE OBJECT
+GdObject *gd_object_new_filled_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                        GdElement elem, GdElement fill_elem)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_FILLED_RECTANGLE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->element = elem;
+  newobj->fill_element = fill_elem;
+
+  return newobj;
+}
+
+// create a raster object
+GdObject *gd_object_new_raster(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                              int dx, int dy, GdElement elem)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_RASTER;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->dx = dx;
+  newobj->dy = dy;
+  newobj->element = elem;
+
+  return newobj;
+}
+
+// create a raster object
+GdObject *gd_object_new_join(GdObjectLevels levels, int dx, int dy,
+                            GdElement search, GdElement replace)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_JOIN;
+  newobj->dx = dx;
+  newobj->dy = dy;
+  newobj->element = search;
+  newobj->fill_element = replace;
+
+  return newobj;
+}
+
+// create a new boundary fill object
+GdObject *gd_object_new_floodfill_border(GdObjectLevels levels, int x1, int y1,
+                                        GdElement fill, GdElement border)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_FLOODFILL_BORDER;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->element = border;
+  newobj->fill_element = fill;
+
+  return newobj;
+}
+
+GdObject *gd_object_new_floodfill_replace(GdObjectLevels levels, int x1, int y1,
+                                         GdElement fill, GdElement to_replace)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_FLOODFILL_REPLACE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->element = to_replace;
+  newobj->fill_element = fill;
+
+  return newobj;
+}
+
+GdObject *gd_object_new_maze(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                            int wall_w, int path_w, GdElement wall_e, GdElement path_e,
+                            int horiz_percent, const int seed[5])
+{
+  int i;
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_MAZE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->dx = wall_w;
+  newobj->dy = path_w;
+  newobj->element = wall_e;
+  newobj->fill_element = path_e;
+  newobj->horiz = horiz_percent;
+
+  for (i = 0; i < 5; ++i)
+    newobj->seed[i] = seed[i];
+
+  return newobj;
+}
+
+GdObject *gd_object_new_maze_unicursal(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                      int wall_w, int path_w, GdElement wall_e, GdElement path_e,
+                                      int horiz_percent, const int seed[5])
+{
+  int i;
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_MAZE_UNICURSAL;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->dx = wall_w;
+  newobj->dy = path_w;
+  newobj->element = wall_e;
+  newobj->fill_element = path_e;
+  newobj->horiz = horiz_percent;
+
+  for (i = 0; i < 5; ++i)
+    newobj->seed[i] = seed[i];
+
+  return newobj;
+}
+
+GdObject *gd_object_new_maze_braid(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                  int wall_w, int path_w, GdElement wall_e, GdElement path_e,
+                                  int horiz_percent, const int seed[5])
+{
+  int i;
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_MAZE_BRAID;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->dx = wall_w;
+  newobj->dy = path_w;
+  newobj->element = wall_e;
+  newobj->fill_element = path_e;
+  newobj->horiz = horiz_percent;
+
+  for (i = 0; i < 5; ++i)
+    newobj->seed[i] = seed[i];
+
+  return newobj;
+}
+
+GdObject *gd_object_new_random_fill(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                   const int seed[5], GdElement initial,
+                                   const GdElement random[4], const int prob[4],
+                                   GdElement replace_only, boolean c64)
+{
+  int i;
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_RANDOM_FILL;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->fill_element = initial;
+
+  for (i = 0; i < 5; ++i)
+    newobj->seed[i] = seed[i];
+
+  for (i = 0; i < 4; ++i)
+  {
+    newobj->random_fill[i] = random[i];
+    newobj->random_fill_probability[i] = prob[i];
+  }
+
+  newobj->element = replace_only;
+  newobj->c64_random = c64;
+
+  return newobj;
+}
+
+GdObject *gd_object_new_copy_paste(GdObjectLevels levels, int x1, int y1, int x2, int y2,
+                                  int dx, int dy, boolean mirror, boolean flip)
+{
+  GdObject *newobj = checked_calloc(sizeof(GdObject));
+
+  newobj->levels = levels;
+  newobj->type = GD_COPY_PASTE;
+  newobj->x1 = x1;
+  newobj->y1 = y1;
+  newobj->x2 = x2;
+  newobj->y2 = y2;
+  newobj->dx = dx;
+  newobj->dy = dy;
+  newobj->mirror = mirror;
+  newobj->flip = flip;
+
+  return newobj;
+}
+
+// create new object from bdcff description.
+// return new object if ok; return null if failed.
+GdObject *gd_object_new_from_string(char *str)
+{
+  char *equalsign;
+  char *name, *param;
+  GdObject object;
+  char elem0[100], elem1[100];
+
+  equalsign = strchr(str, '=');
+  if (!equalsign)
+    return NULL;
+
+  // split string by replacing the equal sign with zero
+  *equalsign = '\0';
+  name = str;
+  param = equalsign + 1;
+
+  // INDIVIDUAL POINT CAVE OBJECT
+  if (strcasecmp(name, "Point") == 0)
+  {
+    object.type = GD_POINT;
+    if (sscanf(param, "%d %d %s", &object.x1, &object.y1, elem0) == 3)
+    {
+      object.element = gd_get_element_from_string(elem0);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // LINE OBJECT
+  if (strcasecmp(name, "Line") == 0)
+  {
+    object.type = GD_LINE;
+    if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
+    {
+      object.element = gd_get_element_from_string(elem0);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // RECTANGLE OBJECT
+  if (strcasecmp(name, "Rectangle") == 0)
+  {
+    if (sscanf(param, "%d %d %d %d %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0) == 5)
+    {
+      object.type = GD_RECTANGLE;
+      object.element = gd_get_element_from_string (elem0);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // FILLED RECTANGLE OBJECT
+  if (strcasecmp(name, "FillRect") == 0)
+  {
+    int paramcount;
+
+    paramcount = sscanf(param, "%d %d %d %d %s %s", &object.x1, &object.y1, &object.x2, &object.y2, elem0, elem1);
+    object.type = GD_FILLED_RECTANGLE;
+
+    if (paramcount == 6)
+    {
+      object.element = gd_get_element_from_string (elem0);
+      object.fill_element = gd_get_element_from_string (elem1);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    if (paramcount == 5)
+    {
+      object.element = object.fill_element = gd_get_element_from_string (elem0);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // RASTER
+  if (strcasecmp(name, "Raster") == 0)
+  {
+    int nx, ny;
+
+    if (sscanf(param, "%d %d %d %d %d %d %s", &object.x1, &object.y1, &nx, &ny, &object.dx, &object.dy, elem0) == 7)
+    {
+      nx--;
+      ny--;
+      object.x2 = object.x1 + nx * object.dx;
+      object.y2 = object.y1 + ny * object.dy;
+      object.type = GD_RASTER;
+      object.element = gd_get_element_from_string (elem0);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // JOIN
+  if (strcasecmp(name, "Join") == 0 ||
+      strcasecmp(name, "Add") == 0)
+  {
+    if (sscanf(param, "%d %d %s %s", &object.dx, &object.dy, elem0, elem1) == 4)
+    {
+      object.type = GD_JOIN;
+      object.element = gd_get_element_from_string (elem0);
+      object.fill_element = gd_get_element_from_string (elem1);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // FILL TO BORDER OBJECT
+  if (strcasecmp(name, "BoundaryFill") == 0)
+  {
+    if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
+    {
+      object.type = GD_FLOODFILL_BORDER;
+      object.fill_element = gd_get_element_from_string (elem0);
+      object.element = gd_get_element_from_string (elem1);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // REPLACE FILL OBJECT
+  if (strcasecmp(name, "FloodFill") == 0)
+  {
+    if (sscanf(param, "%d %d %s %s", &object.x1, &object.y1, elem0, elem1) == 4)
+    {
+      object.type = GD_FLOODFILL_REPLACE;
+      object.fill_element = gd_get_element_from_string (elem0);
+      object.element = gd_get_element_from_string (elem1);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // MAZE OBJECT
+  // MAZE UNICURSAL OBJECT
+  // BRAID MAZE OBJECT
+  if (strcasecmp(name, "Maze") == 0)
+  {
+    char type[100] = "perfect";
+
+    if (sscanf(param, "%d %d %d %d %d %d %d %d %d %d %d %d %s %s %s", &object.x1, &object.y1, &object.x2, &object.y2, &object.dx, &object.dy, &object.horiz, &object.seed[0], &object.seed[1], &object.seed[2], &object.seed[3], &object.seed[4], elem0, elem1, type) >= 14)
+    {
+      if (strcasecmp(type, "unicursal") == 0)
+       object.type = GD_MAZE_UNICURSAL;
+      else if (strcasecmp(type, "perfect") == 0)
+       object.type = GD_MAZE;
+      else if (strcasecmp(type, "braid") == 0)
+       object.type = GD_MAZE_BRAID;
+      else
+      {
+       Warn("unknown maze type: %s, defaulting to perfect", type);
+       object.type = GD_MAZE;
+      }
+
+      object.element = gd_get_element_from_string (elem0);
+      object.fill_element = gd_get_element_from_string (elem1);
+
+      return get_memcpy(&object, sizeof (GdObject));
+    }
+
+    return NULL;
+  }
+
+  // RANDOM FILL OBJECT
+  if (strcasecmp(name, "RandomFill") == 0 ||
+      strcasecmp(name, "RandomFillC64") == 0)
+  {
+    static char **words = NULL;
+    int l, i;
+
+    object.type = GD_RANDOM_FILL;
+    if (strcasecmp(name, "RandomFillC64") == 0)
+      // totally the same, but uses c64 random generator
+      object.c64_random = TRUE;
+    else
+      object.c64_random = FALSE;
+
+    if (sscanf(param, "%d %d %d %d", &object.x1, &object.y1, &object.x2, &object.y2) != 4)
+      return NULL;
+
+    if (words)
+      freeStringArray(words);
+
+    words = getSplitStringArray(param, " ", -1);
+    l = getStringArrayLength(words);
+
+    if (l < 10 || l > 19)
+      return NULL;
+
+    for (i = 0; i < 5; i++)
+      if (sscanf(words[4 + i], "%d", &object.seed[i]) != 1)
+       return NULL;
+
+    object.fill_element = gd_get_element_from_string(words[9]);
+
+    for (i = 0; i < 4; i++)
+    {
+      object.random_fill[i] = O_DIRT;
+      object.random_fill_probability[i] = 0;
+    }
+
+    for (i = 10; i < l - 1; i += 2)
+    {
+      object.random_fill[(i - 10) / 2] = gd_get_element_from_string(words[i]);
+      if (sscanf(words[i + 1], "%d", &object.random_fill_probability[(i - 10) / 2]) == 0)
+       return NULL;
+    }
+
+    object.element = O_NONE;
+
+    if (l > 10 && l % 2 == 1)
+      object.element = gd_get_element_from_string(words[l - 1]);
+
+    return get_memcpy(&object, sizeof (GdObject));
+  }
+
+  // COPY PASTE OBJECT
+  if (strcasecmp(name, "CopyPaste") == 0)
+  {
+    char mirror[100] = "nomirror";
+    char flip[100] = "noflip";
+    object.type = GD_COPY_PASTE;
+
+    object.flip = object.mirror = FALSE;
+
+    if (sscanf(param, "%d %d %d %d %d %d %s %s", &object.x1, &object.y1, &object.x2, &object.y2, &object.dx, &object.dy, mirror, flip) < 6)
+      return NULL;
+
+    // MIRROR PROPERTY
+    if (strcasecmp(mirror, "mirror") == 0)
+      object.mirror = TRUE;
+    else if (strcasecmp(mirror, "nomirror") == 0)
+      object.mirror = FALSE;
+    else
+      Warn("invalid setting for copypaste mirror property: %s", mirror);
+
+    // FLIP PROPERTY
+    if (strcasecmp(flip, "flip") == 0)
+      object.flip = TRUE;
+    else if (strcasecmp(flip, "noflip") == 0)
+      object.flip = FALSE;
+    else
+      Warn("invalid setting for copypaste flip property: %s", flip);
+
+    return get_memcpy(&object, sizeof(GdObject));
+  }
+
+  return NULL;
+}
+
+// drawing a line, using bresenham's
+static void draw_line (GdCave *cave, const GdObject *object)
+{
+  int x, y, x1, y1, x2, y2;
+  boolean steep;
+  int error, dx, dy, ystep;
+
+  x1 = object->x1;
+  y1 = object->y1, x2 = object->x2;
+  y2 = object->y2;
+  steep = ABS (y2 - y1) > ABS (x2 - x1);
+
+  if (steep)
+  {
+    x = x1;
+    x1 = y1;
+    y1 = x;
+    x = x2;
+    x2 = y2;
+    y2 = x;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+    x = y1;
+    y1 = y2;
+    y2 = x;
+  }
+
+  dx = x2 - x1;
+  dy = ABS (y2 - y1);
+  y = y1;
+  error = 0;
+  ystep = (y1 < y2) ? 1 : -1;
+
+  for (x = x1; x <= x2; x++)
+  {
+    if (steep)
+      gd_cave_store_rc (cave, y, x, object->element, object);
+    else
+      gd_cave_store_rc (cave, x, y, object->element, object);
+
+    error += dy;
+
+    if (error * 2 >= dx)
+    {
+      y += ystep;
+      error -= dx;
+    }
+  }
+}
+
+
+
+static void draw_fill_replace_proc(GdCave *cave, int x, int y, const GdObject *object)
+{
+  // fill with border so we do not come back
+  gd_cave_store_rc(cave, x, y, object->fill_element, object);
+
+  if (x > 0 && gd_cave_get_rc(cave, x - 1, y) == object->element)
+    draw_fill_replace_proc(cave, x - 1, y, object);
+
+  if (y > 0 && gd_cave_get_rc(cave, x, y - 1) == object->element)
+    draw_fill_replace_proc(cave, x, y - 1, object);
+
+  if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) == object->element)
+    draw_fill_replace_proc(cave, x + 1, y, object);
+
+  if (y < cave->h - 1 && gd_cave_get_rc(cave, x, y + 1) == object->element)
+    draw_fill_replace_proc(cave, x, y + 1, object);
+}
+
+static void draw_fill_replace (GdCave *cave, const GdObject *object)
+{
+  // check bounds
+  if (object->x1 < 0 ||
+      object->y1 < 0 ||
+      object->x1 >= cave->w ||
+      object->y1 >= cave->h)
+    return;
+
+  if (object->element == object->fill_element)
+    return;
+
+  // this procedure fills the area with the object->element.
+  draw_fill_replace_proc(cave, object->x1, object->y1, object);
+}
+
+static void draw_fill_border_proc (GdCave *cave, int x, int y, const GdObject *object)
+{
+  // fill with border so we do not come back
+  gd_cave_store_rc(cave, x, y, object->element, object);
+
+  if (x > 0 && gd_cave_get_rc(cave, x - 1, y) != object->element)
+    draw_fill_border_proc(cave, x - 1, y, object);
+
+  if (y > 0 && gd_cave_get_rc(cave, x, y - 1) != object->element)
+    draw_fill_border_proc(cave, x, y - 1, object);
+
+  if (x < cave->w - 1 && gd_cave_get_rc(cave, x + 1, y) != object->element)
+    draw_fill_border_proc(cave, x + 1, y, object);
+
+  if (y < cave->h-1 && gd_cave_get_rc(cave, x, y + 1) != object->element)
+    draw_fill_border_proc(cave, x, y + 1, object);
+}
+
+static void draw_fill_border (GdCave *cave, const GdObject *object)
+{
+  int x, y;
+
+  // check bounds
+  if (object->x1 < 0 ||
+      object->y1 < 0 ||
+      object->x1 >= cave->w ||
+      object->y1 >= cave->h)
+    return;
+
+  // this procedure fills the area with the object->element.
+  draw_fill_border_proc(cave, object->x1, object->y1, object);
+
+  // after the fill, we change all filled cells to the fill_element.
+  // we find those by looking at the object_order[][]
+  for (y = 0; y < cave->h; y++)
+    for (x = 0; x < cave->w; x++)
+      if (cave->objects_order[y][x] == object)
+       cave->map[y][x] = object->fill_element;
+}
+
+// rectangle, frame only
+static void draw_rectangle(GdCave *cave, const GdObject *object)
+{
+  int x1, y1, x2, y2, x, y;
+
+  // reorder coordinates if not drawing from northwest to southeast
+  x1 = object->x1;
+  y1 = object->y1, x2 = object->x2;
+  y2 = object->y2;
+
+  if (y1 > y2)
+  {
+    y = y1;
+    y1 = y2;
+    y2 = y;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+  }
+
+  for (x = x1; x <= x2; x++)
+  {
+    gd_cave_store_rc(cave, x, object->y1, object->element, object);
+    gd_cave_store_rc(cave, x, object->y2, object->element, object);
+  }
+
+  for (y = y1; y <= y2; y++)
+  {
+    gd_cave_store_rc(cave, object->x1, y, object->element, object);
+    gd_cave_store_rc(cave, object->x2, y, object->element, object);
+  }
+}
+
+// rectangle, filled one
+static void draw_filled_rectangle(GdCave *cave, const GdObject *object)
+{
+  int x1, y1, x2, y2, x, y;
+
+  // reorder coordinates if not drawing from northwest to southeast
+  x1 = object->x1;
+  y1 = object->y1, x2 = object->x2;
+  y2 = object->y2;
+
+  if (y1 > y2)
+  {
+    y = y1;
+    y1 = y2;
+    y2 = y;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+  }
+
+  for (y = y1; y <= y2; y++)
+    for (x = x1; x <= x2; x++)
+      gd_cave_store_rc(cave, x, y, (y == object->y1 ||
+                                   y == object->y2 ||
+                                   x == object->x1 ||
+                                   x == object->x2) ? object->element : object->fill_element, object);
+}
+
+// something like ordered fill, increment is dx and dy.
+static void draw_raster(GdCave *cave, const GdObject *object)
+{
+  int x, y, x1, y1, x2, y2;
+  int dx, dy;
+
+  // reorder coordinates if not drawing from northwest to southeast
+  x1 = object->x1;
+  y1 = object->y1;
+  x2 = object->x2;
+  y2 = object->y2;
+
+  if (y1 > y2)
+  {
+    y = y1;
+    y1 = y2;
+    y2 = y;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+  }
+
+  dx = object->dx;
+
+  if (dx < 1)
+    dx = 1;
+
+  dy = object->dy;
+
+  if (dy < 1)
+    dy = 1;
+
+  for (y = y1; y <= y2; y += dy)
+    for (x = x1; x <= x2; x += dx)
+      gd_cave_store_rc(cave, x, y, object->element, object);
+}
+
+// find every object, and put fill_element next to it. relative coordinates dx,dy
+static void draw_join(GdCave *cave, const GdObject *object)
+{
+  int x, y;
+
+  for (y = 0; y < cave->h; y++)
+  {
+    for (x = 0; x < cave->w; x++)
+    {
+      if (cave->map[y][x] == object->element)
+      {
+       int nx = x + object->dx;
+       int ny = y + object->dy;
+       // this one implements wraparound for joins.
+       // it is needed by many caves in profi boulder series
+       while (nx >= cave->w)
+         nx -= cave->w, ny++;
+
+       gd_cave_store_rc(cave, nx, ny, object->fill_element, object);
+      }
+    }
+  }
+}
+
+// create a maze in a boolean **maze.
+// recursive algorithm.
+static void mazegen(GdRand *rand, boolean **maze, int width, int height, int x, int y, int horiz)
+{
+  int dirmask = 15;
+
+  maze[y][x] = TRUE;
+  while (dirmask != 0)
+  {
+    int dir;
+
+    // horiz or vert
+    dir = gd_rand_int_range(rand, 0, 100) < horiz ? 2 : 0;
+
+    // if no horizontal movement possible, choose vertical
+    if (dir == 2 && (dirmask & 12) == 0)
+      dir = 0;
+    else if (dir == 0 && (dirmask & 3) == 0)    // and vice versa
+      dir = 2;
+
+    dir += gd_rand_int_range(rand, 0, 2);                // dir
+    if (dirmask & (1 << dir))
+    {
+      dirmask &= ~(1 << dir);
+
+      switch (dir)
+      {
+       case 0:    // up
+         if (y >= 2 && !maze[y - 2][x])
+         {
+           maze[y - 1][x] = TRUE;
+           mazegen(rand, maze, width, height, x, y - 2, horiz);
+         }
+         break;
+
+       case 1:    // down
+         if (y < height-2 && !maze[y + 2][x]) {
+           maze[y + 1][x] = TRUE;
+           mazegen(rand, maze, width, height, x, y + 2, horiz);
+         }
+         break;
+
+       case 2:    // left
+         if (x >= 2 && !maze[y][x - 2]) {
+           maze[y][x - 1] = TRUE;
+           mazegen(rand, maze, width, height, x - 2, y, horiz);
+         }
+         break;
+
+       case 3:    // right
+         if (x < width - 2 && !maze[y][x + 2]) {
+           maze[y][x + 1] = TRUE;
+           mazegen(rand, maze, width, height, x + 2, y, horiz);
+         }
+         break;
+
+       default:
+         break;
+      }
+    }
+  }
+}
+
+static void braidmaze(GdRand *rand, boolean **maze, int w, int h)
+{
+  int x, y;
+
+  for (y = 0; y < h; y += 2)
+  {
+    for (x = 0; x < w; x += 2)
+    {
+      int closed = 0, dirs = 0;
+      int closed_dirs[4];
+
+      // if it is the edge of the map, OR no path carved, then we can't go in that direction.
+      if (x < 1 || !maze[y][x - 1])
+      {
+       // closed from this side.
+       closed++;
+
+       // if not the edge, we might open this wall (carve a path) to remove a dead end
+       if (x > 0)
+         closed_dirs[dirs++] = GD_MV_LEFT;
+      }
+
+      // other 3 directions similar
+      if (y < 1 || !maze[y - 1][x])
+      {
+       closed++;
+       if (y > 0)
+         closed_dirs[dirs++] = GD_MV_UP;
+      }
+
+      if (x >= w - 1 || !maze[y][x + 1])
+      {
+       closed++;
+       if (x < w - 1)
+         closed_dirs[dirs++] = GD_MV_RIGHT;
+      }
+
+      if (y >= h - 1 || !maze[y + 1][x]) {
+       closed++;
+       if (y < h - 1)
+         closed_dirs[dirs++] = GD_MV_DOWN;
+      }
+
+      // if closed from 3 sides, then it is a dead end. also check dirs != 0,
+      // that might fail for a 1x1 maze :)
+      if (closed == 3 && dirs != 0)
+      {
+       // make up a random direction, and open in that direction, so dead end is removed
+       int dir = closed_dirs[gd_rand_int_range(rand, 0, dirs)];
+
+       switch (dir)
+       {
+         case GD_MV_LEFT:
+           maze[y][x - 1] = TRUE; break;
+         case GD_MV_UP:
+           maze[y - 1][x] = TRUE; break;
+         case GD_MV_RIGHT:
+           maze[y][x + 1] = TRUE; break;
+         case GD_MV_DOWN:
+           maze[y + 1][x] = TRUE; break;
+       }
+      }
+    }
+  }
+}
+
+static void draw_maze(GdCave *cave, const GdObject *object, int level)
+{
+  int x, y;
+  boolean **map;
+  int x1 = object->x1;
+  int y1 = object->y1;
+  int x2 = object->x2;
+  int y2 = object->y2;
+  int w, h, path, wall;
+  int xk, yk;
+  GdRand *rand;
+  int i,j;
+
+  // change coordinates if not in correct order
+  if (y1 > y2)
+  {
+    y = y1;
+    y1 = y2;
+    y2 = y;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+  }
+
+  wall = object->dx;
+  if (wall < 1)
+    wall = 1;
+
+  path = object->dy;
+  if (path < 1)
+    path = 1;
+
+  /*
+    calculate the width and height of the maze.
+    n = number of passages, path = path width, wall = wall width, maze = maze width.
+    if given the number of passages, the width of the maze is:
+
+    n * path + (n - 1) * wall = maze
+    n * path + n * wall - wall = maze
+    n * (path + wall) = maze + wall
+    n = (maze + wall) / (path + wall)
+  */
+
+  // number of passages for each side
+  w = (x2 - x1 + 1 + wall) / (path + wall);
+  h = (y2 - y1 + 1 + wall) / (path + wall);
+
+  // and we calculate the size of the internal map
+  if (object->type == GD_MAZE_UNICURSAL)
+  {
+    // for unicursal maze, width and height must be mod2 = 0,
+    // and we will convert to paths & walls later
+    w = w / 2 * 2;
+    h = h / 2 * 2;
+  }
+  else
+  {
+    // for normal maze
+    w = 2 * (w - 1) + 1;
+    h = 2 * (h - 1) + 1;
+  }
+
+  // twodimensional boolean array to generate map in
+  map = checked_malloc((h) * sizeof(boolean *));
+  for (y = 0; y < h; y++)
+    map[y] = checked_calloc(w * sizeof(boolean));
+
+  // start generation, if map is big enough.
+  // otherwise the application would crash, as the editor places maze objects
+  // during mouse click & drag that have no sense
+  rand = gd_rand_new_with_seed(object->seed[level] == -1 ?
+                              gd_rand_int(cave->random) : object->seed[level]);
+
+  if (w >= 1 && h >= 1)
+    mazegen(rand, map, w, h, 0, 0, object->horiz);
+
+  if (object->type == GD_MAZE_BRAID)
+    braidmaze(rand, map, w, h);
+
+  gd_rand_free(rand);
+
+  if (w >= 1 && h >= 1 && object->type == GD_MAZE_UNICURSAL)
+  {
+    boolean **unicursal;
+
+    // convert to unicursal maze
+    /* original:
+        xxx x
+          x x
+        xxxxx
+
+        unicursal:
+        xxxxxxx xxx
+        x     x x x
+        xxxxx x x x
+            x x x x
+        xxxxx xxx x
+        x         x
+        xxxxxxxxxxx
+    */
+
+    unicursal = checked_malloc((h * 2 - 1) * sizeof(boolean *));
+
+    for (y = 0; y < h * 2 - 1; y++)
+      unicursal[y] = checked_calloc((w * 2 - 1) * sizeof(boolean));
+
+    for (y = 0; y < h; y++)
+    {
+      for(x = 0; x < w; x++)
+      {
+       if (map[y][x]) {
+         unicursal[y * 2][x * 2] = TRUE;
+         unicursal[y * 2][x * 2 + 2] = TRUE;
+         unicursal[y * 2 + 2][x * 2] = TRUE;
+         unicursal[y * 2 + 2][x * 2 + 2] = TRUE;
+
+         if (x < 1      || !map[y][x - 1]) unicursal[y * 2 + 1][x * 2] = TRUE;
+         if (y < 1      || !map[y - 1][x]) unicursal[y * 2][x * 2 + 1] = TRUE;
+         if (x >= w - 1 || !map[y][x + 1]) unicursal[y * 2 + 1][x * 2 + 2] = TRUE;
+         if (y >= h - 1 || !map[y + 1][x]) unicursal[y * 2 + 2][x * 2 + 1] = TRUE;
+       }
+      }
+    }
+
+    // free original map
+    for (y = 0; y < h; y++)
+      free(map[y]);
+    free(map);
+
+    // change to new map - the unicursal maze
+    map = unicursal;
+    h = h * 2 - 1;
+    w = w * 2 - 1;
+  }
+
+  // copy map to cave with correct elements and size
+  /* now copy the map into the cave. the copying works like this...
+     pwpwp
+     xxxxx p
+     x x   w
+     x xxx p
+     x     w
+     xxxxx p
+     columns and rows denoted with "p" are to be drawn with path width,
+     the others with wall width. */
+
+  yk = y1;
+
+  for (y = 0; y < h; y++)
+  {
+    for (i = 0; i < (y % 2 == 0 ? path : wall); i++)
+    {
+      xk = x1;
+
+      for (x = 0; x < w; x++)
+       for (j = 0; j < (x % 2 == 0 ? path : wall); j++)
+         gd_cave_store_rc(cave, xk++, yk, map[y][x] ? object->fill_element : object->element, object);
+
+      // if width is smaller than requested, fill with wall
+      for(x = xk; x <= x2; x++)
+       gd_cave_store_rc(cave, x, yk, object->element, object);
+
+      yk++;
+    }
+  }
+
+  // if height is smaller than requested, fill with wall
+  for (y = yk; y <= y2; y++)
+    for (x = x1; x <= x2; x++)
+      gd_cave_store_rc(cave, x, y, object->element, object);
+
+  // free map
+  for (y = 0; y < h; y++)
+    free(map[y]);
+  free(map);
+}
+
+static void draw_random_fill(GdCave *cave, const GdObject *object, int level)
+{
+  int x, y;
+  int x1 = object->x1;
+  int y1 = object->y1;
+  int x2 = object->x2;
+  int y2 = object->y2;
+  GdRand *rand;
+  GdC64RandomGenerator c64_rand;
+  unsigned int seed;
+
+  // -1 means that it should be different every time played.
+  if (object->seed[level] == -1)
+    seed = gd_rand_int(cave->random);
+  else
+    seed = object->seed[level];
+
+  rand = gd_rand_new_with_seed(seed);
+  // for c64 random, use the 2*8 lsb.
+  gd_c64_random_set_seed(&c64_rand, seed / 256 % 256, seed % 256);
+
+  // change coordinates if not in correct order
+  if (y1 > y2)
+  {
+    y = y1;
+    y1 = y2;
+    y2 = y;
+  }
+
+  if (x1 > x2)
+  {
+    x = x1;
+    x1 = x2;
+    x2 = x;
+  }
+
+  for (y = y1; y <= y2; y++)
+  {
+    for (x = x1; x <= x2; x++)
+    {
+      unsigned int randm;
+      GdElement element;
+
+      if (object->c64_random)
+       // use c64 random generator
+       randm = gd_c64_random(&c64_rand);
+      else
+       // use the much better glib random generator
+       randm = gd_rand_int_range(rand, 0, 256);
+
+      element = object->fill_element;
+      if (randm < object->random_fill_probability[0])
+       element = object->random_fill[0];
+      if (randm < object->random_fill_probability[1])
+       element = object->random_fill[1];
+      if (randm < object->random_fill_probability[2])
+       element = object->random_fill[2];
+      if (randm < object->random_fill_probability[3])
+       element = object->random_fill[3];
+
+      if (object->element == O_NONE ||
+         gd_cave_get_rc(cave, x, y) == object->element)
+       gd_cave_store_rc(cave, x, y, element, object);
+    }
+  }
+
+  gd_rand_free(rand);
+}
+
+
+static void draw_copy_paste(GdCave *cave, const GdObject *object)
+{
+  int x1 = object->x1, y1 = object->y1, x2 = object->x2, y2 = object->y2;
+  int x, y;    // iterators
+  int w, h;
+  GdElement *clipboard;
+
+  // reorder coordinates if not drawing from northwest to southeast
+  if (x2 < x1)
+  {
+    x = x2;
+    x2 = x1;
+    x1 = x;
+  }
+
+  if (y2 < y1)
+  {
+    y = y2;
+    y2 = y1;
+    y1 = y;
+  }
+
+  w = x2 - x1 + 1;
+  h = y2 - y1 + 1;
+
+  clipboard = checked_malloc((w * h) * sizeof(GdElement));
+
+  // copy to "clipboard"
+  for (y = 0; y < h; y++)
+    for (x = 0; x < w; x++)
+      clipboard[y * w + x] = gd_cave_get_rc(cave, x + x1, y + y1);
+
+  for (y = 0; y < h; y++)
+  {
+    int ydest;
+
+    ydest = object->flip ? h - 1 - y : y;
+
+    for (x = 0; x < w; x++)
+    {
+      int xdest;
+
+      xdest = object->mirror ? w - 1 - x : x;
+
+      // dx and dy are used here are "paste to" coordinates
+      gd_cave_store_rc(cave, object->dx + xdest, object->dy + ydest,
+                      clipboard[y * w + x], object);
+    }
+  }
+
+  free(clipboard);
+}
+
+// draw the specified game object into cave's data.
+// also remember, which cell was set by which cave object.
+void gd_cave_draw_object(GdCave *cave, const GdObject *object, int level)
+{
+  switch (object->type)
+  {
+    case GD_POINT:
+      // single point
+      gd_cave_store_rc(cave, object->x1, object->y1, object->element, object);
+      break;
+
+    case GD_LINE:
+      draw_line(cave, object);
+      break;
+
+    case GD_RECTANGLE:
+      draw_rectangle(cave, object);
+      break;
+
+    case GD_FILLED_RECTANGLE:
+      draw_filled_rectangle(cave, object);
+      break;
+
+    case GD_RASTER:
+      draw_raster(cave, object);
+      break;
+
+    case GD_JOIN:
+      draw_join(cave, object);
+      break;
+
+    case GD_FLOODFILL_BORDER:
+      draw_fill_border(cave, object);
+      break;
+
+    case GD_FLOODFILL_REPLACE:
+      draw_fill_replace(cave, object);
+      break;
+
+    case GD_MAZE:
+    case GD_MAZE_UNICURSAL:
+    case GD_MAZE_BRAID:
+      draw_maze(cave, object, level);
+      break;
+
+    case GD_RANDOM_FILL:
+      draw_random_fill(cave, object, level);
+      break;
+
+    case GD_COPY_PASTE:
+      draw_copy_paste(cave, object);
+      break;
+
+    case NONE:
+      break;
+
+    default:
+      Error("Unknown object %d", object->type);
+      break;
+  }
+}
+
+// load cave to play... also can be called rendering the cave elements
+GdCave *gd_cave_new_rendered(const GdCave *data, const int level, const unsigned int seed)
+{
+  GdCave *cave;
+  GdElement element;
+  int x, y;
+  List *iter;
+
+  // make a copy
+  cave = gd_cave_new_from_cave(data);
+  cave->rendered = level + 1;
+
+  cave->render_seed = seed;
+  cave->random = gd_rand_new_with_seed(cave->render_seed);
+
+  // maps needed during drawing and gameplay
+  cave->objects_order = gd_cave_map_new(cave, void *);
+
+  cave->time                   = data->level_time[level];
+  cave->timevalue              = data->level_timevalue[level];
+  cave->diamonds_needed        = data->level_diamonds[level];
+  cave->magic_wall_time        = data->level_magic_wall_time[level];
+  cave->slime_permeability     = data->level_slime_permeability[level];
+  cave->slime_permeability_c64 = data->level_slime_permeability_c64[level];
+  cave->time_bonus             = data->level_bonus_time[level];
+  cave->time_penalty           = data->level_penalty_time[level];
+  cave->amoeba_time            = data->level_amoeba_time[level];
+  cave->amoeba_max_count       = data->level_amoeba_threshold[level];
+  cave->amoeba_2_time          = data->level_amoeba_2_time[level];
+  cave->amoeba_2_max_count     = data->level_amoeba_2_threshold[level];
+  cave->hatching_delay_time    = data->level_hatching_delay_time[level];
+  cave->hatching_delay_frame   = data->level_hatching_delay_frame[level];
+
+  if (!cave->map)
+  {
+    // if we have no map, fill with predictable random generator.
+    cave->map = gd_cave_map_new(cave, GdElement);
+
+    // IF CAVE HAS NO MAP, USE THE RANDOM NUMBER GENERATOR
+    // init c64 randomgenerator
+    if (data->level_rand[level] < 0)
+      gd_cave_c64_random_set_seed(cave, gd_rand_int_range(cave->random, 0, 256),
+                                 gd_rand_int_range(cave->random, 0, 256));
+    else
+      gd_cave_c64_random_set_seed(cave, 0, data->level_rand[level]);
+
+    // generate random fill
+    //
+    // start from row 1 (0 skipped), and fill also the borders on left and right hand side,
+    // as c64 did. this way works the original random generator the right way.
+    // also, do not fill last row, that is needed for the random seeds to be correct
+    // after filling! predictable slime will use it.
+    for (y = 1; y < cave->h - 1; y++)
+    {
+      for (x = 0; x < cave->w; x++)
+      {
+       unsigned int randm;
+
+       if (data->level_rand[level] < 0)
+         // use the much better glib random generator
+         randm = gd_rand_int_range(cave->random, 0, 256);
+       else
+         // use c64
+         randm = gd_cave_c64_random(cave);
+
+       element = data->initial_fill;
+       if (randm < data->random_fill_probability[0])
+         element = data->random_fill[0];
+       if (randm < data->random_fill_probability[1])
+         element = data->random_fill[1];
+       if (randm < data->random_fill_probability[2])
+         element = data->random_fill[2];
+       if (randm < data->random_fill_probability[3])
+         element = data->random_fill[3];
+
+       gd_cave_store_rc(cave, x, y, element, NULL);
+      }
+    }
+
+    // draw initial border
+    for (y = 0; y < cave->h; y++)
+    {
+      gd_cave_store_rc(cave, 0,           y, cave->initial_border, NULL);
+      gd_cave_store_rc(cave, cave->w - 1, y, cave->initial_border, NULL);
+    }
+
+    for (x = 0; x < cave->w; x++)
+    {
+      gd_cave_store_rc(cave, x,           0, cave->initial_border, NULL);
+      gd_cave_store_rc(cave, x, cave->h - 1, cave->initial_border, NULL);
+    }
+
+    // store if random number generator needs correction for static random seed
+    cave->slime_correct_random = (data->level_rand[level] >= 0);
+  }
+  else
+  {
+    // IF CAVE HAS A MAP, SIMPLY USE IT... no need to fill with random elements
+
+    // initialize c64 predictable random for slime.
+    // the values were taken from afl bd, see docs/internals.txt
+    gd_cave_c64_random_set_seed(cave, 0, 0x1e);
+
+    // correct random number generator if cave was rendered with static random seed
+    if (cave->slime_correct_random)
+    {
+      int i;
+
+      // set static random seed used when rendering the cave
+      gd_cave_c64_random_set_seed(cave, 0, data->level_rand[level]);
+
+      for (i = 0; i < cave->w * (cave->h - 2); i++)
+       gd_cave_c64_random(cave);
+    }
+  }
+
+  if (data->level_slime_seed_c64[level] != -1)
+  {
+    // if a specific slime seed is requested, change it now.
+
+    gd_cave_c64_random_set_seed(cave,
+                               data->level_slime_seed_c64[level] / 256,
+                               data->level_slime_seed_c64[level] % 256);
+  }
+
+  // render cave objects above random data or map
+  for (iter = data->objects; iter; iter = list_next(iter))
+  {
+    GdObject *object = (GdObject *)iter->data;
+
+    if (object->levels & gd_levels_mask[level])
+      gd_cave_draw_object(cave, iter->data, level);
+  }
+
+  // check if we use c64 ckdelay or milliseconds for timing
+  if (cave->scheduling == GD_SCHEDULING_MILLISECONDS)
+    cave->speed = data->level_speed[level];        // exact timing
+  else
+  {
+    // delay loop based timing... set something for first iteration,
+    // then later it will be calculated
+    cave->speed = 120;
+
+    // this one may be used by iterate routine to calculate actual delay
+    // if c64scheduling is selected
+    cave->c64_timing = data->level_ckdelay[level];
+  }
+
+  gd_cave_correct_visible_size(cave);
+
+  return cave;
+}
+
+/*
+  render cave at specified level.
+  copy result to the map; remove objects.
+  the cave will be map-based.
+*/
+void gd_flatten_cave(GdCave *cave, const int level)
+{
+  GdCave *rendered;
+
+  if (cave == NULL)
+    return;
+
+  // render cave at specified level to obtain map. seed = 0
+  rendered = gd_cave_new_rendered(cave, level, 0);
+
+  // forget old map without objects
+  gd_cave_map_free(cave->map);
+
+  // copy new map to cave
+  cave->map = gd_cave_map_dup(rendered, map);
+  gd_cave_free(rendered);
+
+  // forget objects
+  list_foreach(cave->objects, (list_fn) free, NULL);
+  cave->objects = NULL;
+}
diff --git a/src/game_bd/bd_caveobject.h b/src/game_bd/bd_caveobject.h
new file mode 100644 (file)
index 0000000..13dbcff
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVEOBJECT_H
+#define BD_CAVEOBJECT_H
+
+#include "bd_cave.h"
+
+
+typedef enum _gd_object_type
+{
+  NONE,                     // this one to be zero.
+  GD_POINT,                 // single point of object1
+  GD_LINE,                  // line from (1) to (2) of object1
+  GD_RECTANGLE,             // rectangle with corners (1) and (2) of object1
+  GD_FILLED_RECTANGLE,      // rectangle with corners (1) and (2) of object1, filled with object2
+  GD_RASTER,                // aligned plots
+  GD_JOIN,                  // every object1 has an object2 next to it, relative (dx,dy)
+  GD_FLOODFILL_REPLACE,     // fill by replacing
+  GD_FLOODFILL_BORDER,      // fill to another element, a border
+  GD_MAZE,                  // maze
+  GD_MAZE_UNICURSAL,        // unicursal maze
+  GD_MAZE_BRAID,            // braid maze
+  GD_RANDOM_FILL,           // random fill
+  GD_COPY_PASTE,            // copy & paste with optional mirror and flip
+} GdObjectType;
+
+typedef enum _gd_object_levels
+{
+  GD_OBJECT_LEVEL1 = 1<<0,
+  GD_OBJECT_LEVEL2 = 1<<1,
+  GD_OBJECT_LEVEL3 = 1<<2,
+  GD_OBJECT_LEVEL4 = 1<<3,
+  GD_OBJECT_LEVEL5 = 1<<4,
+
+  GD_OBJECT_LEVEL_ALL = (GD_OBJECT_LEVEL1 |
+                        GD_OBJECT_LEVEL2 |
+                        GD_OBJECT_LEVEL3 |
+                        GD_OBJECT_LEVEL4 |
+                        GD_OBJECT_LEVEL5),
+} GdObjectLevels;
+
+extern GdObjectLevels gd_levels_mask[];
+
+typedef struct _gd_object
+{
+  GdObjectType type;                    // type
+  GdObjectLevels levels;                // levels to show this object on
+
+  int x1, y1;                           // (first) coordinate
+  int x2, y2;                           // second coordinate
+  int dx, dy;                           // distance of elements for raster or join
+  GdElement element, fill_element;      // element type
+
+  int seed[5];                          // for maze and random fill
+  int horiz;                            // for maze
+
+  boolean mirror, flip;                 // for copy
+
+  boolean c64_random;                   // random fill objects: use c64 random generator
+
+  GdElement random_fill[4];
+  int random_fill_probability[4];
+} GdObject;
+
+GdObject *gd_object_new_point(GdObjectLevels levels, int x, int y, GdElement elem);
+GdObject *gd_object_new_line(GdObjectLevels levels, int x1, int y1, int x2, int y2, GdElement elem);
+GdObject *gd_object_new_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2, GdElement elem);
+GdObject *gd_object_new_filled_rectangle(GdObjectLevels levels, int x1, int y1, int x2, int y2, GdElement elem, GdElement fill_elem);
+GdObject *gd_object_new_raster(GdObjectLevels levels, int x1, int y1, int x2, int y2, int dx, int dy, GdElement elem);
+GdObject *gd_object_new_join(GdObjectLevels levels, int dx, int dy, GdElement search, GdElement replace);
+GdObject *gd_object_new_floodfill_border(GdObjectLevels levels, int x1, int y1, GdElement fill, GdElement border);
+GdObject *gd_object_new_floodfill_replace(GdObjectLevels levels, int x1, int y1, GdElement fill, GdElement to_replace);
+GdObject *gd_object_new_maze(GdObjectLevels levels, int x1, int y1, int x2, int y2, int wall_w, int path_w, GdElement wall_e, GdElement path_e, int horiz_percent, const int seed[5]);
+GdObject *gd_object_new_maze_unicursal(GdObjectLevels levels, int x1, int y1, int x2, int y2, int wall_w, int path_w, GdElement wall_e, GdElement path_e, int horiz_percent, const int seed[5]);
+GdObject *gd_object_new_maze_braid(GdObjectLevels levels, int x1, int y1, int x2, int y2, int wall_w, int path_w, GdElement wall_e, GdElement path_e, int horiz_percent, const int seed[5]);
+GdObject *gd_object_new_random_fill(GdObjectLevels levels, int x1, int y1, int x2, int y2, const int seed[5], GdElement initial, const GdElement random[4], const int prob[4], GdElement replace_only, boolean c64);
+GdObject *gd_object_new_copy_paste(GdObjectLevels levels, int x1, int y1, int x2, int y2, int dx, int dy, boolean mirror, boolean flip);
+
+void gd_cave_draw_object(GdCave *cave, const GdObject *object, int level);
+char *gd_object_get_bdcff(const GdObject *object);
+GdObject *gd_object_new_from_string(char *str);
+
+GdCave *gd_cave_new_rendered(const GdCave *data, const int level, unsigned int seed);
+void gd_flatten_cave(GdCave *cave, const int level);
+
+#endif // BD_CAVEOBJECT_H
diff --git a/src/game_bd/bd_caveset.c b/src/game_bd/bd_caveset.c
new file mode 100644 (file)
index 0000000..0ee9c3b
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/stat.h>
+
+#include "main_bd.h"
+
+
+// this stores the caves.
+List *gd_caveset;
+
+// the data of the caveset: name, highscore, max number of lives, etc.
+GdCavesetData *gd_caveset_data;
+
+// is set to true, when the caveset was edited since the last save.
+boolean gd_caveset_edited;
+
+// last selected-to-play cave
+int gd_caveset_last_selected;
+int gd_caveset_last_selected_level;
+
+// list of possible extensions which can be opened
+char *gd_caveset_extensions[] =
+{
+  "*.gds",
+  "*.bd",
+  "*.bdr",
+  "*.brc",
+
+  NULL
+};
+
+#define CAVESET_OFFSET(property) (STRUCT_OFFSET(GdCavesetData, property))
+
+const GdStructDescriptor gd_caveset_properties[] =
+{
+  // default data
+  {"", GD_TAB, 0, N_("Caveset data")},
+  {"Name", GD_TYPE_STRING, 0, N_("Name"), CAVESET_OFFSET(name), 1, N_("Name of the game")},
+  {"Description", GD_TYPE_STRING, 0, N_("Description"), CAVESET_OFFSET(description), 1, N_("Some words about the game")},
+  {"Author", GD_TYPE_STRING, 0, N_("Author"), CAVESET_OFFSET(author), 1, N_("Name of author")},
+  {"Date", GD_TYPE_STRING, 0, N_("Date"), CAVESET_OFFSET(date), 1, N_("Date of creation")},
+  {"WWW", GD_TYPE_STRING, 0, N_("WWW"), CAVESET_OFFSET(www), 1, N_("Web page or e-mail address")},
+  {"Difficulty", GD_TYPE_STRING, 0, N_("Difficulty"), CAVESET_OFFSET(difficulty), 1, N_("Difficulty (informative)")},
+
+  {"Lives", GD_TYPE_INT, 0, N_("Initial lives"), CAVESET_OFFSET(initial_lives), 1, N_("Number of lives you get at game start."), 3, 9},
+  {"Lives", GD_TYPE_INT, 0, N_("Maximum lives"), CAVESET_OFFSET(maximum_lives), 1, N_("Maximum number of lives you can have by collecting bonus points."), 3, 99},
+  {"BonusLife", GD_TYPE_INT, 0, N_("Bonus life score"), CAVESET_OFFSET(bonus_life_score), 1, N_("Number of points to collect for a bonus life."), 100, 5000},
+
+  {"Story", GD_TYPE_LONGSTRING, 0, N_("Story"), CAVESET_OFFSET(story), 1, N_("Long description of the game.")},
+  {"Remark", GD_TYPE_LONGSTRING, 0, N_("Remark"), CAVESET_OFFSET(remark), 1, N_("Remark (informative).")},
+
+  {"TitleScreen", GD_TYPE_LONGSTRING, GD_DONT_SHOW_IN_EDITOR, N_("Title screen"), CAVESET_OFFSET(title_screen), 1, N_("Title screen image")},
+  {"TitleScreenScroll", GD_TYPE_LONGSTRING, GD_DONT_SHOW_IN_EDITOR, N_("Title screen, scrolling"), CAVESET_OFFSET(title_screen_scroll), 1, N_("Scrolling background for title screen image")},
+
+  {NULL},
+};
+
+static GdPropertyDefault caveset_defaults[] =
+{
+  // default data
+  {CAVESET_OFFSET(initial_lives), 3},
+  {CAVESET_OFFSET(maximum_lives), 9},
+  {CAVESET_OFFSET(bonus_life_score), 500},
+
+  {-1},
+};
+
+GdCavesetData *gd_caveset_data_new(void)
+{
+  GdCavesetData *data;
+
+  data = checked_calloc(sizeof(GdCavesetData));
+
+  gd_struct_set_defaults_from_array(data, gd_caveset_properties, caveset_defaults);
+
+  if (leveldir_current != NULL)
+    data->levelset_subdir = getStringCopy(leveldir_current->subdir);
+
+  return data;
+}
+
+void gd_caveset_data_free(GdCavesetData *data)
+{
+  int i;
+
+  // free strings
+  for (i = 0; gd_caveset_properties[i].identifier != NULL; i++)
+    if (gd_caveset_properties[i].type == GD_TYPE_LONGSTRING)
+      checked_free(STRUCT_MEMBER(char *, data, gd_caveset_properties[i].offset));
+
+  checked_free(data->levelset_subdir);
+
+  checked_free(data);
+}
+
+// ============================================================================
+// Misc caveset functions
+// ============================================================================
+
+// Clears all caves in the caveset. also to be called at application start
+void gd_caveset_clear(void)
+{
+  if (gd_caveset)
+  {
+    list_foreach(gd_caveset, (list_fn) gd_cave_free, NULL);
+    list_free(gd_caveset);
+    gd_caveset = NULL;
+  }
+
+  if (gd_caveset_data)
+  {
+    gd_caveset_data_free(gd_caveset_data);
+    gd_caveset_data = NULL;
+  }
+
+  // always newly create this
+  // create pseudo cave containing default values
+  gd_caveset_data = gd_caveset_data_new();
+
+  if (leveldir_current != NULL)
+    gd_strcpy(gd_caveset_data->name, leveldir_current->name);
+}
+
+// return number of caves currently in memory.
+int gd_caveset_count(void)
+{
+  return list_length(gd_caveset);
+}
+
+// return index of first selectable cave
+static int caveset_first_selectable_cave_index(void)
+{
+  List *iter;
+  int i;
+
+  for (i = 0, iter = gd_caveset; iter != NULL; i++, iter = iter->next)
+  {
+    GdCave *cave = (GdCave *)iter->data;
+
+    if (cave->selectable)
+      return i;
+  }
+
+  Warn("no selectable cave in caveset!");
+
+  // and return the first one.
+  return 0;
+}
+
+// return a cave identified by its index
+GdCave *gd_return_nth_cave(const int cave)
+{
+  return list_nth_data(gd_caveset, cave);
+}
+
+// get a selected cave from the loaded caveset (original, unmodified cave)
+GdCave *gd_get_original_cave_from_caveset(const int cave)
+{
+  // get specified cave from caveset already stored in memory
+  GdCave *original_cave = gd_return_nth_cave(cave);
+
+  return original_cave;
+}
+
+// get a selected cave from the loaded caveset (cave prepared for playing)
+GdCave *gd_get_prepared_cave_from_caveset(const int cave, const int level)
+{
+  // get specified cave from caveset already stored in memory
+  GdCave *original_cave = gd_return_nth_cave(cave);
+
+  // get prepared cave from original cave
+  GdCave *prepared_cave = gd_get_prepared_cave(original_cave, level);
+
+  return prepared_cave;
+}
+
+// get a cave prepared for playing from a given original, unmodified cave (with seed)
+GdCave *gd_get_prepared_cave(const GdCave *original_cave, const int level)
+{
+  // get rendered cave using the selected seed for playing
+  GdCave *prepared_cave = gd_cave_new_rendered(original_cave, level, game_bd.random_seed);
+
+  // initialize some cave variables (like player position)
+  gd_cave_setup_for_game(prepared_cave);
+
+  return prepared_cave;
+}
+
+// colors: 4: purple  3: ciklamen 2: orange 1: blue 0: green
+static GdElement brc_import_table[] =
+{
+  /* 0 */
+  O_SPACE, O_DIRT, O_BRICK, O_MAGIC_WALL, O_PRE_OUTBOX, O_OUTBOX, O_UNKNOWN, O_STEEL,
+  O_H_EXPANDING_WALL, O_H_EXPANDING_WALL /* scanned */, O_FIREFLY_1 /* scanned */, O_FIREFLY_1 /* scanned */, O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+
+  /* 1 */
+  O_BUTTER_1 /* scanned */, O_BUTTER_1 /* scanned */, O_BUTTER_1, O_BUTTER_2, O_BUTTER_3, O_BUTTER_4, O_PLAYER, O_PLAYER /* scanned */,
+  O_STONE, O_STONE /* scanned */, O_STONE_F, O_STONE_F /* scanned */, O_DIAMOND, O_DIAMOND /* scanned */, O_DIAMOND_F, O_DIAMOND_F /* scanned */,
+
+  /* 2 */
+  O_NONE /* WILL_EXPLODE_THING */, O_EXPLODE_1, O_EXPLODE_2, O_EXPLODE_3, O_EXPLODE_4, O_EXPLODE_5, O_NONE /* WILL EXPLODE TO DIAMOND_THING */, O_PRE_DIA_1,
+  O_PRE_DIA_2, O_PRE_DIA_3, O_PRE_DIA_4, O_PRE_DIA_5, O_AMOEBA, O_AMOEBA /* scanned */, O_SLIME, O_NONE,
+
+  /* 3 */
+  O_CLOCK, O_NONE /* clock eaten */, O_INBOX, O_PRE_PL_1, O_PRE_PL_2, O_PRE_PL_3, O_NONE, O_NONE,
+  O_NONE, O_NONE, O_V_EXPANDING_WALL, O_NONE, O_VOODOO, O_UNKNOWN, O_EXPANDING_WALL, O_EXPANDING_WALL /* sc */,
+
+  /* 4 */
+  O_FALLING_WALL, O_FALLING_WALL_F, O_FALLING_WALL_F /* scanned */, O_UNKNOWN, O_ACID, O_ACID /* scanned */, O_NITRO_PACK, O_NITRO_PACK /* scanned */,
+  O_NITRO_PACK_F, O_NITRO_PACK_F /* scanned */, O_NONE, O_NONE, O_NONE, O_NONE, O_NONE, O_NONE,
+
+  /* 5 */
+  O_NONE /* bomb explosion utolso */, O_UNKNOWN, O_NONE /* solid bomb glued */, O_UNKNOWN, O_STONE_GLUED, O_UNKNOWN, O_DIAMOND_GLUED, O_UNKNOWN,
+  O_UNKNOWN, O_UNKNOWN, O_NONE, O_NONE, O_NONE, O_NONE, O_NONE, O_NONE,
+
+  /* 6 */
+  O_ALT_FIREFLY_1 /* scanned */, O_ALT_FIREFLY_1 /* scanned */, O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4, O_PLAYER_BOMB, O_PLAYER_BOMB /* scanned */,
+  O_BOMB, O_BOMB_TICK_1, O_BOMB_TICK_2, O_BOMB_TICK_3, O_BOMB_TICK_4, O_BOMB_TICK_5, O_BOMB_TICK_6, O_BOMB_TICK_7,
+
+  /* 7 */
+  O_BOMB_TICK_7, O_BOMB_EXPL_1, O_BOMB_EXPL_2, O_BOMB_EXPL_3, O_BOMB_EXPL_4, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+};
+
+static GdElement brc_effect_table[] =
+{
+  O_STEEL, O_DIRT, O_SPACE, O_STONE, O_STONE_F, O_STONE_GLUED, O_DIAMOND, O_DIAMOND_F, O_DIAMOND_GLUED, O_PRE_DIA_1,
+  O_PLAYER, O_PRE_PL_1, O_PLAYER_BOMB, O_PRE_OUTBOX, O_OUTBOX, O_FIREFLY_1, O_FIREFLY_2, O_FIREFLY_3, O_FIREFLY_4,
+  O_BUTTER_1, O_BUTTER_2, O_BUTTER_3, O_BUTTER_4, O_BRICK, O_MAGIC_WALL, O_H_EXPANDING_WALL, O_V_EXPANDING_WALL, O_EXPANDING_WALL,
+  O_FALLING_WALL, O_FALLING_WALL_F, O_AMOEBA, O_SLIME, O_ACID, O_VOODOO, O_CLOCK, O_BOMB, O_UNKNOWN, O_UNKNOWN, O_UNKNOWN,
+  O_ALT_FIREFLY_1, O_ALT_FIREFLY_2, O_ALT_FIREFLY_3, O_ALT_FIREFLY_4, O_ALT_BUTTER_1, O_ALT_BUTTER_2, O_ALT_BUTTER_3, O_ALT_BUTTER_4,
+  O_EXPLODE_1, O_BOMB_EXPL_1, O_UNKNOWN,
+};
+
+static GdColor brc_color_table[] =
+{
+  0x518722, 0x3a96fa, 0xdb7618, 0xff3968,
+  0x9b5fff, 0x0ee06c, 0xc25ea6, 0xf54826,
+  0xf1ff26,
+};
+
+static GdColor brc_color_table_comp[] =
+{
+  0x582287, 0xfa9d39, 0x187ddb, 0x38ffd1,
+  0xc1ff5e, 0xe00d81, 0x5dc27a, 0x27d3f5,
+  0x3526ff,
+};
+
+static GdElement brc_effect(byte byt)
+{
+  if (byt >= ARRAY_SIZE(brc_effect_table))
+  {
+    Warn("invalid element identifier for brc effect: %02x", byt);
+
+    return O_UNKNOWN;
+  }
+
+  return brc_effect_table[byt];
+}
+
+static void brc_import(byte *data)
+{
+  int x, y;
+  int level;
+
+  // we import 100 caves, and the put them in the correct order.
+  GdCave *imported[100];
+  boolean import_effect;
+
+  gd_caveset_clear();
+
+  // this is some kind of a version number
+  import_effect = FALSE;
+
+  switch (data[23])
+  {
+    case 0x0:
+      // nothing to do
+      break;
+
+    case 0xde:
+      // import effects
+      import_effect = TRUE;
+      break;
+
+    default:
+      Warn("unknown brc version %02x", data[23]);
+      break;
+  }
+
+  for (level = 0; level < 5; level++)
+  {
+    int cavenum;
+    int i;
+
+    for (cavenum = 0; cavenum < 20; cavenum++)
+    {
+      GdCave *cave;
+
+      // 5 levels, 20 caves, 24 bytes - max 40*2 properties for each cave
+      int c = 5 * 20 * 24;
+
+      int datapos = (cavenum * 5 +level) * 24 + 22;
+      int colind;
+
+      cave = gd_cave_new();
+      imported[level * 20 + cavenum] = cave;
+
+      if (cavenum < 16)
+       snprintf(cave->name, sizeof(GdString), "Cave %c/%d", 'A' + cavenum,
+                level + 1);
+      else
+       snprintf(cave->name, sizeof(GdString), "Intermission %d/%d",
+                cavenum - 15, level + 1);
+
+      // fixed intermission caves; are smaller.
+      if (cavenum >= 16)
+      {
+       cave->w = 20;
+       cave->h = 12;
+      }
+
+      cave->map = gd_cave_map_new(cave, GdElement);
+
+      for (y = 0; y < cave->h; y++)
+      {
+       for (x = 0; x < cave->w; x++)
+       {
+         byte import;
+
+         import = data[y + level * 24 + cavenum * 24 * 5 + x * 24 * 5 * 20];
+
+         // if (i == printcave) g_print("%2x", import);
+         if (import < ARRAY_SIZE(brc_import_table))
+           cave->map[y][x] = brc_import_table[import];
+         else
+           cave->map[y][x] = O_UNKNOWN;
+       }
+      }
+
+      for (i = 0; i < 5; i++)
+      {
+       cave->level_time[i]             = data[0 * c + datapos];
+       cave->level_diamonds[i]         = data[1 * c + datapos];
+       cave->level_magic_wall_time[i]  = data[4 * c + datapos];
+       cave->level_amoeba_time[i]      = data[5 * c + datapos];
+       cave->level_amoeba_threshold[i] = data[6 * c + datapos];
+
+       // bonus time: 100 was added, so it could also be negative
+       cave->level_bonus_time[i]      = (int)data[11 * c + datapos + 1] - 100;
+       cave->level_hatching_delay_frame[i] = data[10 * c + datapos];
+
+       // this was not set in boulder remake.
+       cave->level_speed[i] = 150;
+      }
+
+      cave->diamond_value = data[2 * c + datapos];
+      cave->extra_diamond_value = data[3 * c +datapos];
+
+      // BRC PROBABILITIES
+      /*
+       a typical code example:
+       46:if (random(slime*4)<4) and (tab[x,y+2] = 0) then
+       Begin tab[x,y]:=0;col[x,y+2]:=col[x,y];tab[x,y+2]:=27;mat[x,y+2]:=9;Voice4:=2;end;
+       where slime is the byte loaded from the file as it is.
+       pascal random function generates a random number between 0..limit-1,
+       inclusive, for random(limit).
+
+       so a random number between 0..limit*4-1 is generated.
+       for limit=1, 0..3, which is always < 4, so P=1.
+       for limit=2, 0..7, 0..7 is < 4 in P=50%.
+       for limit=3, 0..11, is < 4 in P=33%.
+       So the probability is exactly 100%/limit.
+       just make sure we do not divide by zero for some broken input.
+      */
+
+      if (data[7 * c + datapos] == 0)
+       Warn("amoeba growth cannot be zero, error at byte %d",
+            data[7 * c + datapos]);
+      else
+       cave->amoeba_growth_prob = 1E6 / data[7 * c + datapos] + 0.5; // 0.5 for rounding
+
+      if (data[8 * c + datapos] == 0)
+       Warn("amoeba growth cannot be zero, error at byte %d",
+            data[8 * c + datapos]);
+      else
+       cave->amoeba_fast_growth_prob = 1E6 / data[8 * c + datapos] + 0.5; // 0.5 for rounding
+
+      cave->slime_predictable = FALSE;
+
+      for (i = 0; i < 5; i++)
+       cave->level_slime_permeability[i] = 1E6 / data[9 * c + datapos] + 0.5;   // 0.5 for rounding
+
+      // probability -> *1E6
+      cave->acid_spread_ratio = 1E6 / data[10 * c + datapos] + 0.5;
+
+      // br only allowed values 1..8 in here, but works the same way. prob -> *1E6
+      cave->pushing_stone_prob = 1E6 / data[11 * c + datapos] + 0.5;
+
+      cave->magic_wall_stops_amoeba = (data[12 * c + datapos + 1] != 0);
+      cave->intermission = (cavenum >= 16 || data[14 * c + datapos + 1] != 0);
+
+      // colors
+      colind = data[31 * c + datapos] % ARRAY_SIZE(brc_color_table);
+      cave->colorb = 0x000000;    // fixed rgb black
+      cave->color0 = 0x000000;    // fixed rgb black
+      cave->color1 = brc_color_table[colind];
+      cave->color2 = brc_color_table_comp[colind];    // complement
+      cave->color3 = 0xffffff;    // white for brick
+      cave->color4 = 0xe5ad23;    // fixed for amoeba
+      cave->color5 = 0x8af713;    // fixed for slime
+
+      if (import_effect)
+      {
+       cave->amoeba_enclosed_effect = brc_effect(data[14 * c + datapos + 1]);
+       cave->amoeba_too_big_effect  = brc_effect(data[15 * c + datapos + 1]);
+       cave->explosion_effect       = brc_effect(data[16 * c + datapos + 1]);
+       cave->bomb_explosion_effect  = brc_effect(data[17 * c + datapos + 1]);
+
+       // 18 solid bomb explode to
+       cave->diamond_birth_effect    = brc_effect(data[19 * c + datapos + 1]);
+       cave->stone_bouncing_effect   = brc_effect(data[20 * c + datapos + 1]);
+       cave->diamond_bouncing_effect = brc_effect(data[21 * c + datapos + 1]);
+       cave->magic_diamond_to        = brc_effect(data[22 * c + datapos + 1]);
+       cave->acid_eats_this          = brc_effect(data[23 * c + datapos + 1]);
+
+       /*
+         slime eats:
+         (diamond,boulder,bomb),
+         (diamond,boulder),
+         (diamond,bomb),
+         (boulder,bomb)
+       */
+       cave->amoeba_enclosed_effect = brc_effect(data[14 * c + datapos + 1]);
+      }
+    }
+  }
+
+  // put them in the caveset - take correct order into consideration.
+  for (level = 0; level < 5; level++)
+  {
+    int cavenum;
+
+    for (cavenum = 0; cavenum < 20; cavenum++)
+    {
+      static const int reorder[] =
+      {
+       0, 1, 2, 3, 16, 4, 5, 6, 7, 17, 8, 9, 10, 11, 18, 12, 13, 14, 15, 19
+      };
+      GdCave *cave = imported[level * 20 + reorder[cavenum]];
+      boolean only_dirt;
+      int x, y;
+
+      // check if cave contains only dirt.
+      // that is an empty cave, and do not import.
+      only_dirt = TRUE;
+
+      for (y = 1; y < cave->h - 1 && only_dirt; y++)
+       for (x = 1; x < cave->w - 1 && only_dirt; x++)
+         if (cave->map[y][x] != O_DIRT)
+           only_dirt = FALSE;
+
+      // append to caveset or forget it.
+      if (!only_dirt)
+       gd_caveset = list_append(gd_caveset, cave);
+      else
+       gd_cave_free(cave);
+    }
+  }
+}
+
+static void caveset_name_set_from_filename(char *filename)
+{
+  char *name;
+  char *c;
+
+  // make up a caveset name from the filename.
+  name = getBaseName(filename);
+  gd_strcpy(gd_caveset_data->name, name);
+  free(name);
+
+  // convert underscores to spaces
+  while ((c = strchr (gd_caveset_data->name, '_')) != NULL)
+    *c = ' ';
+
+  // remove extension
+  if ((c = strrchr (gd_caveset_data->name, '.')) != NULL)
+    *c = 0;
+}
+
+/*
+  Load caveset from file.
+  Loads the caveset from a file.
+
+  File type is autodetected by extension.
+  param filename: Name of file.
+  result: FALSE if failed
+*/
+boolean gd_caveset_load_from_file(char *filename)
+{
+  size_t length;
+  char *buf;
+  List *new_caveset;
+  struct stat st;
+  File *file;
+
+  if (stat(filename, &st) != 0)
+  {
+    Warn("cannot stat() file");
+
+    return FALSE;
+  }
+
+  if (st.st_size > 1048576)
+  {
+    Warn("file bigger than 1MiB, refusing to load");
+
+    return FALSE;
+  }
+
+  if (!(file = openFile(filename, MODE_READ)))
+  {
+    Warn("cannot open file '%s'", filename);
+
+    return FALSE;
+  }
+
+  buf = checked_malloc(st.st_size + 1);
+  length = readFile(file, buf, 1, st.st_size);
+  buf[length] = '\0';
+
+  closeFile(file);
+
+  if (length < st.st_size)
+  {
+    Warn("cannot read file '%s'", filename);
+
+    return FALSE;
+  }
+
+  if (strSuffix(filename, ".brc") ||
+      strSuffix(filename, ".BRC"))
+  {
+    // loading a boulder remake file
+    if (length != 96000)
+    {
+      Warn("BRC files must be 96000 bytes long");
+
+      return FALSE;
+    }
+  }
+
+  if (strSuffix(filename, ".brc") ||
+      strSuffix(filename, ".BRC"))
+  {
+    brc_import((byte *) buf);
+    gd_caveset_edited = FALSE;    // newly loaded cave is not edited
+    gd_caveset_last_selected = caveset_first_selectable_cave_index();
+    gd_caveset_last_selected_level = 0;
+    free(buf);
+    caveset_name_set_from_filename(filename);
+
+    return TRUE;
+  }
+
+  // BDCFF
+  if (gd_caveset_imported_get_format((byte *) buf) == GD_FORMAT_UNKNOWN)
+  {
+    // try to load as bdcff
+    boolean result;
+
+    // bdcff: start another function
+    result = gd_caveset_load_from_bdcff(buf);
+
+    // newly loaded file is not edited.
+    gd_caveset_edited = FALSE;
+
+    gd_caveset_last_selected = caveset_first_selectable_cave_index();
+    gd_caveset_last_selected_level = 0;
+    free(buf);
+
+    return result;
+  }
+
+  // try to load as a binary file, as we know the format
+  new_caveset = gd_caveset_import_from_buffer ((byte *) buf, length);
+  free(buf);
+
+  // if unable to load, exit here. error was reported by import_from_buffer()
+  if (!new_caveset)
+    return FALSE;
+
+  // no serious error :)
+
+  // only clear caveset here. if file read was unsuccessful, caveset remains in memory.
+  gd_caveset_clear();
+
+  gd_caveset = new_caveset;
+
+  // newly loaded cave is not edited
+  gd_caveset_edited = FALSE;
+
+  gd_caveset_last_selected = caveset_first_selectable_cave_index();
+  gd_caveset_last_selected_level = 0;
+  caveset_name_set_from_filename(filename);
+
+  return TRUE;
+}
+
+boolean gd_caveset_save_to_file(const char *filename)
+{
+  GdPtrArray *saved = gd_caveset_save_to_bdcff();
+  boolean success;
+  File *file;
+  int i;
+
+  if ((file = openFile(filename, MODE_WRITE)) != NULL)
+  {
+    for (i = 0; i < saved->size; i++)
+    {
+      writeFile(file, saved->data[i], 1, strlen(saved->data[i]));
+      writeFile(file, "\n", 1, 1);
+    }
+
+    closeFile(file);
+
+    // remember that it is saved
+    gd_caveset_edited = FALSE;
+
+    success = TRUE;
+  }
+  else
+  {
+    Warn("cannot open file '%s'", filename);
+
+    success = FALSE;
+  }
+
+  gd_ptr_array_free(saved, TRUE);
+
+  return success;
+}
+
+
+int gd_cave_check_replays(GdCave *cave, boolean report, boolean remove, boolean repair)
+{
+  List *riter;
+  int wrong = 0;
+
+  riter = cave->replays;
+  while (riter != NULL)
+  {
+    GdReplay *replay = (GdReplay *)riter->data;
+    unsigned int checksum;
+    GdCave *rendered;
+    List *next = riter->next;
+
+    rendered = gd_cave_new_rendered(cave, replay->level, replay->seed);
+    checksum = gd_cave_adler_checksum(rendered);
+    gd_cave_free(rendered);
+
+    replay->wrong_checksum = FALSE;
+
+    // count wrong ones... the checksum might be changed later to "repair"
+    if (replay->checksum != 0 && checksum != replay->checksum)
+      wrong++;
+
+    if (replay->checksum == 0 || repair)
+    {
+      // if no checksum found, add one. or if repair requested, overwrite old one.
+      replay->checksum = checksum;
+    }
+    else
+    {
+      // if has a checksum, compare with this one.
+      if (replay->checksum != checksum)
+      {
+       replay->wrong_checksum = TRUE;
+
+       if (report)
+         Warn("%s: replay played by %s at %s has wrong checksum",
+              cave->name, replay->player_name, replay->date);
+
+       if (remove)
+       {
+         // may remove
+         cave->replays = list_remove_link(cave->replays, riter);
+         gd_replay_free(replay);
+       }
+      }
+    }
+
+    // advance to next list item which we remembered. the current one might have been deleted
+    riter = next;
+  }
+
+  return wrong;
+}
+
+boolean gd_caveset_has_replays(void)
+{
+  List *citer;
+
+  // for all caves
+  for (citer = gd_caveset; citer != NULL; citer = citer->next)
+  {
+    GdCave *cave = (GdCave *)citer->data;
+
+    if (cave->replays)
+      return TRUE;
+  }
+
+  // if neither of the caves had a replay,
+  return FALSE;
+}
diff --git a/src/game_bd/bd_caveset.h b/src/game_bd/bd_caveset.h
new file mode 100644 (file)
index 0000000..7cd23f6
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_CAVESET_H
+#define BD_CAVESET_H
+
+#include "main_bd.h"
+
+
+typedef struct _gd_caveset_data
+{
+  GdString name;                // Name of caveset
+  GdString description;         // Some words about the caveset
+  GdString author;              // Author
+  GdString difficulty;          // difficulty of the caveset, for info purposes
+  GdString www;                 // link to author's webpage
+  GdString date;                // date of creation
+
+  char *story;                  // story for the caves
+  char *remark;                 // notes about the game
+    
+  char *title_screen;           // base64-encoded title screen image
+  char *title_screen_scroll;    // scrolling background for title screen image
+
+  GdString charset;             // these are not used by gdash
+  GdString fontset;
+
+  // these are only for a game.
+  int initial_lives;            // initial lives at game start
+  int maximum_lives;            // maximum lives
+  int bonus_life_score;         // bonus life / number of points
+
+  // and this one the highscores
+  GdHighScore highscore[GD_HIGHSCORE_NUM];
+
+  char *levelset_subdir;       // current level set identifier
+} GdCavesetData;
+
+extern const GdStructDescriptor gd_caveset_properties[];
+
+extern GdCavesetData *gd_caveset_data;
+extern List *gd_caveset;
+extern boolean gd_caveset_edited;
+extern int gd_caveset_last_selected;
+extern int gd_caveset_last_selected_level;
+
+extern char *gd_caveset_extensions[];
+
+// #included cavesets; configdir passed to look for .hsc file
+boolean gd_caveset_load_from_internal(int caveset, const char *configdir);
+const char **gd_caveset_get_internal_game_names(void);
+
+// caveset load from file
+boolean gd_caveset_load_from_file(char *filename);
+// caveset save to bdcff file
+boolean gd_caveset_save_to_file(const char *filename);
+
+// misc caveset functions
+int gd_caveset_count(void);
+void gd_caveset_clear(void);
+GdCave *gd_return_nth_cave(const int cave);
+
+GdCave *gd_get_original_cave_from_caveset(const int cave);
+GdCave *gd_get_prepared_cave_from_caveset(const int cave, const int level);
+GdCave *gd_get_prepared_cave(const GdCave *cave, const int level);
+
+// highscore in config directory
+void gd_save_highscore(const char* directory);
+boolean gd_load_highscore(const char *directory);
+
+GdCavesetData *gd_caveset_data_new(void);
+void gd_caveset_data_free(GdCavesetData *data);
+
+// check replays and optionally remove
+int gd_cave_check_replays(GdCave *cave, boolean report, boolean remove, boolean repair);
+
+boolean gd_caveset_has_replays(void);
+
+#endif // BD_CAVESET_H
diff --git a/src/game_bd/bd_colors.c b/src/game_bd/bd_colors.c
new file mode 100644 (file)
index 0000000..7a9a35a
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+static char *c64_color_names[] =
+{
+  "Black",  "White", "Red",      "Cyan",  "Purple", "Green",      "Blue",      "Yellow",
+  "Orange", "Brown", "LightRed", "Gray1", "Gray2",  "LightGreen", "LightBlue", "Gray3",
+};
+
+static unsigned int c64_colors_vice_old[] =
+{
+  0x000000, 0xFFFFFF, 0x68372b, 0x70a4b2, 0x6f3d86, 0x588d43, 0x352879, 0xb8c76f,
+  0x6f4f25, 0x433900, 0x9a6759, 0x444444, 0x6c6c6c, 0x9ad284, 0x6c5eb5, 0x959595,
+};
+
+static unsigned int c64_colors_vice_new[] =
+{
+  0x000000, 0xffffff, 0x894036, 0x7abfc7, 0x8a46ae, 0x68a941, 0x3e31a2, 0xd0dc71,
+  0x905f25, 0x5c4700, 0xbb776d, 0x555555, 0x808080, 0xacea88, 0x7c70da, 0xababab,
+};
+
+static unsigned int c64_colors_c64_hq[] =
+{
+  0x0A0A0A, 0xFFF8FF, 0x851F02, 0x65CDA8, 0xA73B9F, 0x4DAB19, 0x1A0C92, 0xEBE353,
+  0xA94B02, 0x441E00, 0xD28074, 0x464646, 0x8B8B8B, 0x8EF68E, 0x4D91D1, 0xBABABA,
+};
+
+static unsigned int c64_colors_c64s[] =
+{
+  0x000000, 0xFCFCFC, 0xA80000, 0x54FCFC, 0xA800A8, 0x00A800, 0x0000A8, 0xFCFC00,
+  0xA85400, 0x802C00, 0xFC5454, 0x545454, 0x808080, 0x54FC54, 0x5454FC, 0xA8A8A8,
+};
+
+static unsigned int c64_colors_ccs64[] =
+{
+  0x101010, 0xFFFFFF, 0xE04040, 0x60FFFF, 0xE060E0, 0x40E040, 0x4040E0, 0xFFFF40,
+  0xE0A040, 0x9C7448, 0xFFA0A0, 0x545454, 0x888888, 0xA0FFA0, 0xA0A0FF, 0xC0C0C0,
+};
+
+static unsigned int c64_colors_vice_default[] =
+{
+  0x000000, 0xFDFEFC, 0xBE1A24, 0x30E6C6, 0xB41AE2, 0x1FD21E, 0x211BAE, 0xDFF60A,
+  0xB84104, 0x6A3304, 0xFE4A57, 0x424540, 0x70746F, 0x59FE59, 0x5F53FE, 0xA4A7A2,
+};
+
+static unsigned int c64_colors_frodo[] =
+{
+  0x000000, 0xFFFFFF, 0xCC0000, 0x00FFCC, 0xFF00FF, 0x00CC00, 0x0000CC, 0xFFFF00,
+  0xFF8800, 0x884400, 0xFF8888, 0x444444, 0x888888, 0x88FF88, 0x8888FF, 0xCCCCCC,
+};
+
+static unsigned int c64_colors_godot[] =
+{
+  0x000000, 0xFFFFFF, 0x880000, 0xAAFFEE, 0xCC44CC, 0x00CC55, 0x0000AA, 0xEEEE77,
+  0xDD8855, 0x664400, 0xFE7777, 0x333333, 0x777777, 0xAAFF66, 0x0088FF, 0xBBBBBB,
+};
+
+static unsigned int c64_colors_pc64[] =
+{
+  0x212121, 0xFFFFFF, 0xB52121, 0x73FFFF, 0xB521B5, 0x21B521, 0x2121B5, 0xFFFF21,
+  0xB57321, 0x944221, 0xFF7373, 0x737373, 0x949494, 0x73FF73, 0x7373FF, 0xB5B5B5,
+};
+
+static unsigned int c64_colors_rtadash[]={
+  0x000000, 0xffffff, 0xea3418, 0x58ffff, 0xd82cff, 0x55fb00, 0x4925ff, 0xffff09,
+  0xe66c00, 0x935f00, 0xff7c64, 0x6c6c6c, 0xa1a1a1, 0xafff4d, 0x9778ff, 0xd8d8d8,
+};
+
+// pointer array positions must match palette numbers in header file
+static unsigned int *c64_palettes_pointers[] =
+{
+    c64_colors_vice_new,
+    c64_colors_vice_old,
+    c64_colors_vice_default,
+    c64_colors_c64_hq,
+    c64_colors_c64s,
+    c64_colors_ccs64,
+    c64_colors_frodo,
+    c64_colors_godot,
+    c64_colors_pc64,
+    c64_colors_rtadash,
+
+    NULL
+};
+
+static byte BuiltIn[] =
+{
+  0,0,0,16,16,16,32,32,32,48,48,48,64,64,64,80,80,80,96,96,96,112,112,112,
+  128,128,128,144,144,144,160,160,160,176,176,176,192,192,192,208,208,208,
+  224,224,224,240,240,240,56,0,0,72,16,0,88,32,0,104,48,0,120,64,0,136,80,
+  0,152,96,0,168,112,0,184,128,0,200,144,0,216,160,12,232,176,28,248,192,
+  44,255,208,60,255,224,76,255,240,92,63,0,0,79,2,0,95,18,0,111,34,0,127,
+  50,0,143,66,0,159,82,3,175,98,19,191,114,35,207,130,51,223,146,67,239,162,
+  83,255,178,99,255,194,115,255,210,131,255,226,147,58,0,0,74,0,0,90,6,12,
+  106,22,28,122,38,44,138,54,60,154,70,76,170,86,92,186,102,108,202,118,124,
+  218,134,140,234,150,156,250,166,172,255,182,188,255,198,204,255,214,220,
+  42,0,56,58,0,72,74,1,88,90,17,104,106,33,120,122,49,136,138,65,152,154,
+  81,168,170,97,184,186,113,200,202,129,216,218,145,232,234,161,248,250,177,
+  255,255,193,255,255,209,255,17,0,122,33,0,138,49,1,154,65,17,170,81,33,
+  186,97,49,202,113,65,218,129,81,234,145,97,250,161,113,255,177,129,255,
+  193,145,255,209,161,255,225,177,255,241,193,255,255,209,255,0,0,164,5,0,
+  180,21,8,196,37,24,212,53,40,228,69,56,244,85,72,255,101,88,255,117,104,
+  255,133,120,255,149,136,255,165,152,255,181,168,255,197,184,255,213,200,
+  255,229,216,255,0,0,173,0,3,189,0,19,205,11,35,221,27,51,237,43,67,253,
+  59,83,255,75,99,255,91,115,255,107,131,255,123,147,255,139,163,255,155,
+  179,255,171,195,255,187,211,255,203,227,255,0,0,148,0,16,164,0,32,180,0,
+  48,196,8,64,212,24,80,228,40,96,244,56,112,255,72,128,255,88,144,255,104,
+  160,255,120,176,255,136,192,255,152,208,255,168,224,255,184,240,255,0,14,
+  93,0,30,109,0,46,125,0,62,141,1,78,157,17,94,173,33,110,189,49,126,205,
+  65,142,221,81,158,237,97,174,253,113,190,255,129,206,255,145,222,255,161,
+  238,255,177,254,255,0,26,20,0,42,36,0,58,52,0,74,68,6,90,84,22,106,100,
+  38,122,116,54,138,132,70,154,148,86,170,164,102,186,180,118,202,196,134,
+  218,212,150,234,228,166,250,244,182,255,255,0,31,0,0,47,0,0,63,0,6,79,0,
+  22,95,8,38,111,24,54,127,40,70,143,56,86,159,72,102,175,88,118,191,104,
+  134,207,120,150,223,136,166,239,152,182,255,168,198,255,184,0,31,0,0,47,
+  0,15,63,0,31,79,0,47,95,0,63,111,0,79,127,0,95,143,0,111,159,6,127,175,
+  22,143,191,38,159,207,54,175,223,70,191,239,86,207,255,102,223,255,118,
+  11,24,0,27,40,0,43,56,0,59,72,0,75,88,0,91,104,0,107,120,0,123,136,0,139,
+  152,0,155,168,0,171,184,0,187,200,12,203,216,28,219,232,44,235,248,60,251,
+  255,76,37,13,0,53,29,0,69,45,0,85,61,0,101,77,0,117,93,0,133,109,0,149,
+  125,0,165,141,0,181,157,0,197,173,0,213,189,3,229,205,19,245,221,35,255,
+  237,51,255,253,67,56,0,0,72,16,0,88,32,0,104,48,0,120,64,0,136,80,0,152,
+  96,0,168,112,0,184,128,0,200,144,0,216,160,12,232,176,28,248,192,44,255,
+  208,60,255,224,76,255,240,92
+};
+
+static byte BuiltIn_contrast[] =
+{
+  0,0,0,17,17,17,34,34,34,51,51,51,68,68,68,85,85,85,102,102,102,119,119,
+  119,136,136,136,153,153,153,170,170,170,187,187,187,204,204,204,221,221,
+  221,238,238,238,255,255,255,59,0,0,76,16,0,93,33,0,110,50,0,127,67,0,144,
+  84,0,161,101,0,178,118,0,195,135,0,212,152,0,229,169,13,246,186,30,255,
+  203,47,255,220,64,255,237,81,255,254,98,67,0,0,84,2,0,101,19,0,118,36,0,
+  135,53,0,152,70,0,169,87,3,186,104,20,203,121,37,220,138,54,237,155,71,
+  254,172,88,255,189,105,255,206,122,255,223,139,255,240,156,62,0,0,79,0,
+  0,96,7,12,113,24,29,130,41,46,147,58,63,164,75,80,181,92,97,198,109,114,
+  215,126,131,232,143,148,249,160,165,255,177,182,255,194,199,255,211,216,
+  255,228,233,44,0,59,61,0,76,78,1,93,95,18,110,112,35,127,129,52,144,146,
+  69,161,163,86,178,180,103,195,197,120,212,214,137,229,231,154,246,248,171,
+  255,255,188,255,255,205,255,255,222,255,18,0,130,35,0,147,52,1,164,69,18,
+  181,86,35,198,103,52,215,120,69,232,137,86,249,154,103,255,171,120,255,
+  188,137,255,205,154,255,222,171,255,239,188,255,255,205,255,255,222,255,
+  0,0,174,5,0,191,22,8,208,39,25,225,56,42,242,73,59,255,90,76,255,107,93,
+  255,124,110,255,141,127,255,158,144,255,175,161,255,192,178,255,209,195,
+  255,226,212,255,243,229,255,0,0,184,0,3,201,0,20,218,12,37,235,29,54,252,
+  46,71,255,63,88,255,80,105,255,97,122,255,114,139,255,131,156,255,148,173,
+  255,165,190,255,182,207,255,199,224,255,216,241,255,0,1,157,0,18,174,0,
+  35,191,0,52,208,9,69,225,26,86,242,43,103,255,60,120,255,77,137,255,94,
+  154,255,111,171,255,128,188,255,145,205,255,162,222,255,179,239,255,196,
+  255,255,0,15,99,0,32,116,0,49,133,0,66,150,1,83,167,18,100,184,35,117,201,
+  52,134,218,69,151,235,86,168,252,103,185,255,120,202,255,137,219,255,154,
+  236,255,171,253,255,188,255,255,0,27,22,0,44,39,0,61,56,0,78,73,6,95,90,
+  23,112,107,40,129,124,57,146,141,74,163,158,91,180,175,108,197,192,125,
+  214,209,142,231,226,159,248,243,176,255,255,193,255,255,0,33,0,0,50,0,0,
+  67,0,7,84,0,24,101,9,41,118,26,58,135,43,75,152,60,92,169,77,109,186,94,
+  126,203,111,143,220,128,160,237,145,177,254,162,194,255,179,211,255,196,
+  0,33,0,0,50,0,16,67,0,33,84,0,50,101,0,67,118,0,84,135,0,101,152,0,118,
+  169,6,135,186,23,152,203,40,169,220,57,186,237,74,203,254,91,220,255,108,
+  237,255,125,12,26,0,29,43,0,46,60,0,63,77,0,80,94,0,97,111,0,114,128,0,
+  131,145,0,148,162,0,165,179,0,182,196,0,199,213,13,216,230,30,233,247,47,
+  250,255,64,255,255,81,39,14,0,56,31,0,73,48,0,90,65,0,107,82,0,124,99,0,
+  141,116,0,158,133,0,175,150,0,192,167,0,209,184,0,226,201,3,243,218,20,
+  255,235,37,255,252,54,255,255,71,59,0,0,76,16,0,93,33,0,110,50,0,127,67,
+  0,144,84,0,161,101,0,178,118,0,195,135,0,212,152,0,229,169,13,246,186,30,
+  255,203,47,255,220,64,255,237,81,255,254,98
+};
+
+static byte Default[] =
+{
+  0,0,0,28,28,28,57,57,57,89,89,89,121,121,121,146,146,146,171,171,171,188,
+  188,188,205,205,205,217,217,217,230,230,230,236,236,236,242,242,242,248,
+  248,248,255,255,255,255,255,255,57,23,1,94,35,4,131,48,8,165,71,22,200,
+  95,36,227,120,32,255,145,29,255,171,29,255,197,29,255,206,52,255,216,76,
+  255,230,81,255,244,86,255,249,119,255,255,152,255,255,152,69,25,4,114,30,
+  17,159,36,30,179,58,32,200,81,34,227,105,32,255,129,30,255,140,37,255,152,
+  44,255,174,56,255,197,69,255,197,89,255,198,109,255,213,135,255,228,161,
+  255,228,161,74,23,4,126,26,13,178,29,23,200,33,25,223,37,28,236,59,56,250,
+  82,85,252,97,97,255,112,110,255,127,126,255,143,143,255,157,158,255,171,
+  173,255,185,189,255,199,206,255,199,206,5,5,104,59,19,109,113,34,114,139,
+  42,140,165,50,166,185,56,186,205,62,207,219,71,221,234,81,235,244,95,245,
+  254,109,255,254,122,253,255,135,251,255,149,253,255,164,255,255,164,255,
+  40,4,121,64,9,132,89,15,144,112,36,157,136,57,170,164,65,195,192,74,220,
+  208,84,237,224,94,255,233,109,255,242,124,255,248,138,255,255,152,255,254,
+  161,255,254,171,255,254,171,255,53,8,138,66,10,173,80,12,208,100,40,208,
+  121,69,208,141,75,212,162,81,217,176,88,236,190,96,255,197,107,255,204,
+  119,255,209,131,255,215,144,255,219,157,255,223,170,255,223,170,255,5,30,
+  129,6,38,165,8,47,202,38,61,212,68,76,222,79,90,238,90,104,255,101,117,
+  255,113,131,255,128,145,255,144,160,255,151,169,255,159,178,255,175,190,
+  255,192,203,255,192,203,255,12,4,139,34,24,160,56,45,181,72,62,199,88,79,
+  218,97,89,236,107,100,255,122,116,255,138,132,255,145,142,255,153,152,255,
+  165,163,255,177,174,255,184,184,255,192,194,255,192,194,255,29,41,90,29,
+  56,118,29,72,146,28,92,172,28,113,198,50,134,207,72,155,217,78,168,236,
+  85,182,255,112,199,255,140,216,255,147,219,255,155,223,255,175,228,255,
+  195,233,255,195,233,255,47,67,2,57,82,2,68,97,3,65,122,18,62,148,33,74,
+  159,46,87,171,59,92,189,85,97,208,112,105,226,122,114,245,132,124,250,141,
+  135,255,151,154,255,166,173,255,182,173,255,182,10,65,8,13,84,10,16,104,
+  13,19,125,15,22,146,18,25,165,20,28,185,23,30,201,25,33,217,27,71,228,45,
+  110,240,64,120,247,77,131,255,91,154,255,122,178,255,154,178,255,154,4,
+  65,11,5,83,14,6,102,17,7,119,20,8,136,23,9,155,26,11,175,29,72,196,31,134,
+  217,34,143,233,36,153,249,39,168,252,65,183,255,91,201,255,110,220,255,
+  129,220,255,129,2,53,15,7,63,21,12,74,28,45,95,30,79,116,32,89,131,36,100,
+  146,40,130,161,46,161,176,52,169,193,58,178,210,65,196,217,69,214,225,73,
+  228,240,78,242,255,83,242,255,83,38,48,1,36,56,3,35,64,5,81,84,27,128,105,
+  49,151,129,53,175,153,58,194,167,62,213,181,67,219,192,61,225,203,56,226,
+  216,54,227,229,52,239,242,88,251,255,125,251,255,125,64,26,2,88,31,5,112,
+  36,8,141,58,19,171,81,31,181,100,39,191,119,48,208,133,58,225,147,68,237,
+  160,78,249,173,88,252,183,92,255,193,96,255,198,113,255,203,131,255,203,
+  131
+};
+
+static byte Jakub[] =
+{
+  45,45,45,59,59,59,73,73,73,87,87,87,101,101,101,115,115,115,129,129,129,
+  143,143,143,157,157,157,171,171,171,185,185,185,199,199,199,213,213,213,
+  227,227,227,241,241,241,255,255,255,92,35,0,106,49,0,120,63,0,134,77,10,
+  148,91,24,162,105,38,176,119,52,190,133,66,204,147,80,218,161,94,232,175,
+  108,246,189,122,255,203,136,255,217,150,255,231,164,255,245,178,105,20,
+  9,119,34,23,133,48,37,147,62,51,161,76,65,175,90,79,189,104,93,203,118,
+  107,217,132,121,231,146,135,245,160,149,255,174,163,255,188,177,255,202,
+  191,255,216,205,255,230,219,108,10,56,122,24,70,136,38,84,150,52,98,164,
+  66,112,178,80,126,192,94,140,206,108,154,220,122,168,234,136,182,248,150,
+  196,255,164,210,255,178,224,255,192,238,255,206,252,255,220,255,100,5,101,
+  114,19,115,128,33,129,142,47,143,156,61,157,170,75,171,184,89,185,198,103,
+  199,212,117,213,226,131,227,240,145,241,254,159,255,255,173,255,255,187,
+  255,255,201,255,255,215,255,82,7,137,96,21,151,110,35,165,124,49,179,138,
+  63,193,152,77,207,166,91,221,180,105,235,194,119,249,208,133,255,222,147,
+  255,236,161,255,250,175,255,255,189,255,255,203,255,255,217,255,58,16,156,
+  72,30,170,86,44,184,100,58,198,114,72,212,128,86,226,142,100,240,156,114,
+  254,170,128,255,184,142,255,198,156,255,212,170,255,226,184,255,240,198,
+  255,254,212,255,255,226,255,31,30,156,45,44,170,59,58,184,73,72,198,87,
+  86,212,101,100,226,115,114,240,129,128,254,143,142,255,157,156,255,171,
+  170,255,185,184,255,199,198,255,213,212,255,227,226,255,241,240,255,7,46,
+  137,21,60,151,35,74,165,49,88,179,63,102,193,77,116,207,91,130,221,105,
+  144,235,119,158,249,133,172,255,147,186,255,161,200,255,175,214,255,189,
+  228,255,203,242,255,217,255,255,0,62,101,3,76,115,17,90,129,31,104,143,
+  45,118,157,59,132,171,73,146,185,87,160,199,101,174,213,115,188,227,129,
+  202,241,143,216,255,157,230,255,171,244,255,185,255,255,199,255,255,0,75,
+  56,0,89,70,9,103,84,23,117,98,37,131,112,51,145,126,65,159,140,79,173,154,
+  93,187,168,107,201,182,121,215,196,135,229,210,149,243,224,163,255,238,
+  177,255,252,191,255,255,0,82,9,0,96,23,12,110,37,26,124,51,40,138,65,54,
+  152,79,68,166,93,82,180,107,96,194,121,110,208,135,124,222,149,138,236,
+  163,152,250,177,166,255,191,180,255,205,194,255,219,0,83,0,11,97,0,25,111,
+  0,39,125,10,53,139,24,67,153,38,81,167,52,95,181,66,109,195,80,123,209,
+  94,137,223,108,151,237,122,165,251,136,179,255,150,193,255,164,207,255,
+  178,19,78,0,33,92,0,47,106,0,61,120,0,75,134,0,89,148,11,103,162,25,117,
+  176,39,131,190,53,145,204,67,159,218,81,173,232,95,187,246,109,201,255,
+  123,215,255,137,229,255,151,45,67,0,59,81,0,73,95,0,87,109,0,101,123,0,
+  115,137,1,129,151,15,143,165,29,157,179,43,171,193,57,185,207,71,199,221,
+  85,213,235,99,227,249,113,241,255,127,255,255,141,70,51,0,84,65,0,98,79,
+  0,112,93,0,126,107,0,140,121,11,154,135,25,168,149,39,182,163,53,196,177,
+  67,210,191,81,224,205,95,238,219,109,252,233,123,255,247,137,255,255,151
+};
+
+static byte Jakub_contrast[] =
+{
+  0,0,0,17,17,17,34,34,34,50,50,50,67,67,67,85,85,85,101,101,101,118,118,
+  118,136,136,136,153,153,153,170,170,170,186,186,186,203,203,203,220,220,
+  220,237,237,237,254,254,254,57,0,0,74,4,0,91,21,0,108,38,0,125,55,0,142,
+  72,0,159,89,8,176,106,25,193,123,42,210,140,59,227,157,76,244,174,93,254,
+  191,110,255,208,127,255,225,144,254,242,161,72,0,0,89,0,0,106,3,0,123,20,
+  7,140,37,24,157,54,41,174,71,58,191,88,75,208,105,92,225,122,109,242,139,
+  126,255,156,143,255,173,160,255,190,177,254,207,194,254,224,211,76,0,13,
+  93,0,30,110,0,47,127,8,64,144,25,81,161,42,98,178,59,115,195,76,132,212,
+  93,149,229,110,166,246,127,183,254,144,200,254,161,217,255,178,234,255,
+  195,251,255,212,255,66,0,68,83,0,85,100,0,102,117,2,119,134,19,136,151,
+  36,153,168,53,170,185,70,187,202,87,204,219,104,221,236,121,238,253,138,
+  255,254,155,254,255,172,255,254,189,254,254,206,254,44,0,111,61,0,128,78,
+  0,145,95,4,162,112,21,179,129,38,196,146,55,213,163,72,230,180,89,247,197,
+  106,254,214,123,255,231,140,255,248,157,254,255,174,255,254,191,254,254,
+  208,254,15,0,134,32,0,151,49,0,168,66,15,185,83,32,202,100,49,219,117,66,
+  236,134,83,253,151,100,255,168,117,254,185,134,254,202,151,255,219,168,
+  254,236,185,255,253,202,254,255,219,255,0,0,134,0,0,151,16,15,168,33,32,
+  185,50,49,202,68,66,219,85,83,236,102,100,253,119,117,255,135,134,254,152,
+  151,254,170,168,255,186,185,254,204,202,255,220,219,254,237,236,254,0,1,
+  111,0,18,128,0,35,145,4,52,162,21,69,179,38,86,196,55,103,213,72,120,230,
+  89,137,247,106,154,255,123,171,255,140,188,254,157,205,255,174,222,254,
+  191,239,255,208,255,255,0,20,67,0,37,85,0,54,101,0,71,118,0,88,136,17,105,
+  153,34,122,170,50,139,186,67,156,203,84,173,220,101,190,237,118,207,254,
+  136,224,255,153,241,254,169,254,254,187,254,254,0,36,13,0,53,30,0,70,47,
+  0,87,64,0,104,81,7,121,98,24,138,115,41,155,132,58,172,149,75,189,166,92,
+  206,183,109,223,200,126,240,217,143,254,234,160,255,251,177,254,254,0,44,
+  0,0,61,0,0,78,0,0,95,7,0,112,24,10,129,41,27,146,58,44,163,75,61,180,92,
+  78,197,109,95,214,126,112,231,143,129,248,160,146,254,177,163,254,194,180,
+  255,211,0,46,0,0,63,0,0,80,0,0,97,0,9,114,0,26,131,0,43,148,8,60,165,25,
+  77,182,42,94,199,59,111,216,76,128,233,93,145,250,110,162,255,127,179,254,
+  144,196,254,161,0,40,0,0,57,0,2,74,0,19,91,0,36,108,0,53,125,0,70,142,0,
+  87,159,0,104,176,9,121,193,26,138,210,43,155,227,60,172,244,77,189,254,
+  94,206,254,111,223,255,128,0,26,0,16,43,0,34,60,0,50,77,0,67,94,0,84,111,
+  0,101,128,0,118,145,0,135,162,0,152,179,14,169,196,31,186,213,48,204,230,
+  65,220,247,82,237,254,99,255,255,116,30,7,0,47,24,0,64,41,0,81,58,0,98,
+  75,0,115,92,0,132,109,0,149,126,0,166,143,9,183,160,26,200,177,43,217,194,
+  60,234,211,77,251,228,94,254,245,111,255,255,128
+};
+
+static byte Real[] =
+{
+  50,49,50,63,62,63,77,76,77,91,91,91,106,105,106,121,120,121,136,135,136,
+  151,151,151,161,160,161,175,175,175,190,190,190,206,205,206,219,219,219,
+  235,234,235,250,250,250,255,255,255,97,46,0,108,59,0,122,74,0,136,88,0,
+  148,103,12,165,118,27,178,132,42,193,148,58,202,157,67,218,173,83,232,187,
+  98,248,203,114,255,216,127,255,232,143,255,247,159,255,255,174,108,36,0,
+  119,48,0,132,64,3,146,78,17,158,93,34,175,108,49,188,123,65,204,138,80,
+  213,147,91,228,163,105,242,177,121,255,194,137,255,207,151,255,223,166,
+  255,237,181,255,253,196,117,22,24,129,35,36,143,49,52,157,64,67,170,78,
+  80,184,94,96,198,109,111,213,125,127,222,135,135,237,149,150,252,164,165,
+  255,180,181,255,194,196,255,209,211,255,224,225,255,239,240,98,14,113,110,
+  27,124,123,42,138,138,57,152,150,71,165,165,87,181,179,101,195,195,117,
+  209,205,126,218,220,141,233,234,151,247,249,172,255,255,186,255,255,201,
+  255,255,217,255,255,232,255,86,15,135,97,29,144,113,44,158,127,58,172,141,
+  72,186,155,88,199,169,103,213,184,119,229,194,128,237,208,144,252,223,159,
+  255,238,175,255,252,189,255,255,204,255,255,219,255,255,234,255,70,22,149,
+  81,34,160,96,50,172,110,65,187,124,79,200,138,94,214,153,109,227,168,124,
+  242,177,133,251,192,149,255,207,163,255,223,179,255,238,193,255,252,208,
+  255,255,223,255,255,239,255,33,41,148,45,53,159,61,68,173,75,83,186,89,
+  97,199,104,111,213,119,126,226,135,142,242,144,151,250,150,166,255,174,
+  181,255,191,196,255,205,210,255,218,227,255,234,241,255,250,254,255,15,
+  53,132,28,65,141,44,80,155,58,94,170,72,108,183,88,123,197,103,138,210,
+  118,153,226,128,162,235,143,178,249,158,192,255,173,208,255,189,221,255,
+  203,236,255,219,252,255,234,255,255,4,63,112,17,75,121,33,89,136,47,104,
+  150,62,117,164,77,131,178,92,146,193,108,161,210,116,171,217,131,186,231,
+  147,201,246,162,216,255,177,230,255,192,245,255,208,255,255,222,255,255,
+  0,89,24,0,101,38,15,114,53,29,129,68,44,142,80,59,157,96,74,172,111,89,
+  187,126,99,196,135,114,211,150,130,226,165,146,241,181,159,254,195,174,
+  255,210,190,255,226,206,255,241,7,92,0,20,104,0,34,117,0,50,131,0,63,145,
+  11,79,160,27,94,174,42,110,189,59,119,198,68,135,213,83,150,227,99,167,
+  243,115,179,254,128,195,255,143,211,255,160,227,255,176,26,86,0,40,98,0,
+  54,112,0,69,126,0,83,140,0,98,155,7,112,169,22,128,185,38,137,194,47,153,
+  209,62,168,223,77,183,239,92,197,252,107,213,255,123,227,255,139,243,255,
+  153,51,75,0,64,87,0,77,101,0,93,115,0,106,130,0,122,145,0,136,158,15,152,
+  174,31,161,183,40,186,198,56,191,213,72,206,228,88,220,242,102,235,255,
+  117,250,255,133,255,255,149,75,60,0,88,73,0,101,87,0,116,101,0,129,116,
+  0,144,131,7,159,145,22,174,161,38,183,170,46,199,186,62,213,199,77,229,
+  215,93,242,229,107,254,244,122,255,255,139,255,255,154,96,46,0,109,58,0,
+  122,73,0,137,88,0,149,103,10,164,118,27,178,131,42,194,148,58,203,157,68,
+  218,172,83,232,186,98,248,203,115,255,215,127,255,231,145,255,246,159,255,
+  255,175
+};
+
+static byte Real_contrast[] =
+{
+  0,0,0,16,15,16,34,32,34,51,51,51,70,68,70,88,87,88,107,106,107,126,126,
+  126,138,137,138,155,155,155,174,174,174,194,192,194,210,210,210,230,228,
+  230,248,248,248,255,255,255,59,0,0,72,11,0,90,30,0,107,47,0,122,66,0,143,
+  85,0,159,102,0,178,122,10,189,133,21,209,153,41,226,170,60,246,190,80,255,
+  206,96,255,226,116,255,245,135,255,255,154,72,0,0,86,0,0,102,18,0,119,35,
+  0,134,54,0,155,72,0,171,91,19,191,109,37,202,121,51,221,140,68,238,158,
+  88,255,179,108,255,195,126,255,215,144,255,232,163,255,252,181,83,0,0,98,
+  0,0,116,0,3,133,18,21,149,35,37,166,55,57,184,73,76,202,93,96,214,106,106,
+  232,123,124,251,142,143,255,161,163,255,179,181,255,197,200,255,216,217,
+  255,235,236,60,0,78,75,0,92,91,0,109,109,9,127,124,26,143,143,46,163,160,
+  63,180,180,83,197,192,94,209,211,113,227,228,126,245,247,152,255,255,169,
+  255,255,188,255,255,207,255,255,226,255,45,0,106,59,0,117,78,0,134,96,10,
+  152,113,28,169,130,47,185,148,66,202,166,86,222,179,97,232,196,117,251,
+  215,135,255,233,155,255,251,173,255,255,191,255,255,210,255,255,228,255,
+  25,0,123,39,0,137,57,0,152,75,19,170,92,36,186,109,55,204,128,73,220,147,
+  92,238,158,103,250,176,123,255,195,140,255,215,160,255,233,178,255,251,
+  196,255,255,215,255,255,235,255,0,0,122,0,4,135,14,23,153,31,41,169,49,
+  59,185,67,76,202,86,94,219,106,114,238,117,126,248,124,144,255,154,163,
+  255,175,181,255,192,199,255,209,220,255,228,237,255,248,253,255,0,4,102,
+  0,19,113,0,37,130,10,55,149,28,72,165,47,91,183,66,109,199,85,128,219,97,
+  139,230,116,159,247,134,176,255,153,196,255,173,212,255,190,231,255,210,
+  251,255,228,255,255,0,16,77,0,31,88,0,49,107,0,67,124,15,83,142,34,101,
+  159,52,119,178,72,138,199,82,150,207,101,169,225,121,188,243,139,206,255,
+  158,223,255,176,242,255,196,255,255,214,255,255,0,49,0,0,63,0,0,80,4,0,
+  98,23,0,114,37,11,133,57,30,152,76,49,170,94,61,181,106,80,200,124,99,219,
+  143,119,237,163,135,253,180,154,255,199,174,255,219,194,255,237,0,52,0,
+  0,67,0,0,83,0,0,101,0,16,118,0,36,137,0,55,154,0,75,173,11,86,184,23,106,
+  202,41,124,220,61,145,240,81,160,253,97,180,255,116,200,255,137,220,255,
+  157,0,45,0,0,60,0,5,77,0,24,94,0,41,112,0,60,130,0,77,148,0,97,168,0,108,
+  179,0,128,197,15,147,215,34,165,235,52,183,251,71,202,255,91,220,255,111,
+  240,255,128,1,31,0,18,46,0,34,63,0,54,81,0,70,99,0,90,118,0,107,134,0,127,
+  154,0,138,165,0,169,184,8,175,202,28,194,221,47,211,238,65,230,255,83,248,
+  255,103,255,255,123,31,13,0,47,29,0,63,46,0,82,63,0,98,82,0,117,101,0,135,
+  118,0,154,138,0,165,149,0,185,169,15,202,185,34,222,205,54,238,222,71,253,
+  241,90,255,255,111,255,255,129,57,0,0,73,10,0,90,29,0,108,47,0,123,66,0,
+  142,85,0,159,101,0,179,122,10,190,133,23,209,152,41,226,169,60,246,190,
+  81,255,205,96,255,225,118,255,243,135,255,255,155
+};
+
+static byte XFormer[] =
+{
+  0,0,0,32,32,32,64,64,64,97,97,97,125,125,125,145,145,145,161,161,161,178,
+  178,178,190,190,190,202,202,202,214,214,214,226,226,226,234,234,234,242,
+  242,242,250,250,250,255,255,255,24,20,0,48,40,0,97,60,4,121,80,8,141,109,
+  12,157,133,24,178,170,48,190,178,68,198,194,80,210,206,93,218,214,105,222,
+  222,117,226,226,133,230,230,145,234,234,157,238,238,165,36,20,0,56,36,0,
+  80,52,0,113,80,0,145,113,4,174,133,4,190,157,40,198,174,68,206,186,97,214,
+  190,105,222,198,113,230,202,121,238,206,129,242,214,145,246,222,157,250,
+  226,161,44,12,4,72,20,8,109,28,16,145,44,32,178,80,52,186,97,64,198,113,
+  85,206,121,101,214,141,121,218,153,137,222,170,149,226,174,153,230,178,
+  157,230,186,161,234,194,170,238,198,178,44,4,12,89,24,36,149,40,68,170,
+  60,89,182,85,113,194,97,121,202,105,129,210,113,137,214,121,145,218,133,
+  153,222,141,161,226,149,170,230,157,178,234,165,182,238,170,186,242,174,
+  190,48,0,44,80,8,72,113,16,105,157,32,149,194,72,198,214,97,214,222,117,
+  222,226,129,226,230,141,230,234,149,234,238,157,238,238,165,238,238,170,
+  238,238,174,238,238,178,238,242,182,242,20,4,64,40,8,129,89,40,186,109,
+  60,198,129,85,206,141,101,210,153,113,214,161,129,218,170,141,222,178,149,
+  226,186,153,230,190,161,230,194,165,234,198,174,234,202,178,238,206,182,
+  238,0,0,52,16,16,105,40,40,186,72,72,198,97,97,214,109,109,218,121,121,
+  222,133,133,226,145,145,230,157,157,230,165,165,234,174,174,234,178,178,
+  238,186,186,242,194,194,246,198,198,250,4,28,72,8,52,121,12,76,170,16,97,
+  170,36,113,182,56,129,194,68,141,206,80,149,214,97,157,222,113,165,226,
+  125,178,230,137,186,230,149,190,234,157,194,234,165,198,238,170,202,242,
+  4,16,48,8,24,89,12,40,129,20,60,145,32,80,153,60,101,178,85,121,190,97,
+  137,198,109,153,210,117,170,218,125,178,222,133,186,226,145,190,230,153,
+  198,234,161,202,238,170,206,242,0,36,28,4,72,56,8,105,80,12,141,109,16,
+  170,133,24,190,153,56,206,178,72,214,186,89,222,198,101,226,206,113,230,
+  210,129,234,214,145,238,222,161,242,226,178,246,230,182,250,234,0,40,4,
+  0,64,12,4,89,20,20,133,28,36,178,64,56,194,85,76,206,97,89,210,113,97,214,
+  125,121,222,141,145,230,153,157,234,165,165,238,178,174,238,190,186,238,
+  198,190,242,202,12,40,0,24,80,0,36,121,4,56,149,16,72,178,28,89,186,48,
+  105,194,68,117,202,89,133,210,105,145,218,113,153,222,121,161,226,133,170,
+  230,145,182,234,157,194,238,170,198,242,174,20,36,0,44,89,0,68,141,4,93,
+  170,8,117,194,32,137,202,48,153,206,68,161,210,85,170,214,97,178,218,109,
+  186,222,117,190,226,125,194,230,137,202,234,149,210,238,161,214,242,170,
+  32,28,0,76,64,0,113,97,16,133,125,24,194,153,32,210,178,48,222,202,60,230,
+  210,76,234,218,89,234,226,97,238,230,105,238,234,117,242,234,133,246,238,
+  141,246,238,145,250,242,153,32,20,0,52,36,0,89,56,4,129,85,12,170,117,20,
+  182,133,28,194,145,48,202,157,72,214,170,97,218,182,109,222,186,121,226,
+  190,133,230,198,145,234,202,153,234,214,157,238,218,161
+};
+
+// pointer array positions must match palette numbers in header file
+static const byte *atari_palettes_pointers[] =
+{
+  BuiltIn,
+  BuiltIn_contrast,
+  Default,
+  Jakub,
+  Jakub_contrast,
+  Real,
+  Real_contrast,
+  XFormer,
+
+  NULL
+};
+
+static byte Spiff[] =
+{
+  2,5,10,12,16,19,29,28,30,36,43,43,54,53,52,63,68,67,82,79,80,91,94,94,103,
+  102,104,114,116,114,130,128,131,139,143,143,157,153,154,167,167,169,181,
+  180,178,193,196,194,35,2,0,45,13,0,58,27,0,68,43,0,80,54,0,92,68,0,109,
+  80,0,120,94,0,130,102,4,141,117,21,157,129,35,167,142,51,182,154,63,194,
+  168,77,210,180,91,223,196,104,52,0,0,63,8,0,76,16,0,85,34,0,99,46,0,108,
+  61,0,127,72,14,139,85,27,150,93,39,162,107,49,175,120,59,185,134,74,201,
+  144,85,212,158,100,229,171,113,243,188,129,62,0,0,75,0,0,86,0,0,96,26,6,
+  110,38,21,121,52,36,139,63,47,152,77,62,163,85,70,174,99,79,188,111,95,
+  199,126,106,212,136,121,226,151,132,244,163,147,255,178,166,64,0,12,78,
+  0,22,89,0,36,101,15,52,112,32,62,126,46,76,143,58,88,155,72,105,167,79,
+  109,176,93,124,192,106,139,200,120,151,216,132,161,226,146,176,246,158,
+  192,254,173,207,58,0,49,68,0,60,82,0,77,90,19,88,107,30,103,116,46,112,
+  135,58,126,146,71,137,158,80,145,170,92,165,181,106,174,193,120,192,209,
+  131,198,219,145,215,236,158,227,252,174,241,40,0,77,50,0,90,66,3,102,73,
+  24,119,89,35,130,99,49,144,118,61,153,130,74,167,139,83,176,152,96,190,
+  165,108,206,175,123,217,191,133,232,203,148,242,220,160,253,232,176,255,
+  20,0,97,31,0,104,44,14,119,56,28,133,68,40,146,79,53,158,97,65,170,108,
+  80,182,118,87,191,130,101,208,147,113,220,154,128,236,172,138,245,182,153,
+  255,199,165,255,217,180,255,0,0,98,5,8,107,23,20,121,32,34,135,48,45,150,
+  57,59,163,74,71,174,84,85,187,96,94,197,108,107,212,123,120,225,134,134,
+  241,149,145,254,157,160,255,174,172,255,189,187,255,0,6,88,0,15,99,0,27,
+  111,0,41,129,20,52,140,31,66,154,47,78,167,59,93,179,69,101,190,84,115,
+  204,102,127,220,111,142,233,126,152,246,134,167,254,149,180,255,161,196,
+  255,0,13,68,0,23,79,0,35,93,0,48,110,0,60,118,0,73,132,12,86,147,25,102,
+  160,43,110,168,57,124,184,78,136,199,89,150,213,102,161,223,111,176,233,
+  125,189,249,140,205,254,0,20,36,0,30,46,0,41,62,0,56,72,0,66,87,0,80,97,
+  0,93,113,0,108,124,5,118,132,32,131,152,56,144,161,69,158,177,87,169,188,
+  95,183,198,109,196,212,121,213,223,0,25,0,0,35,0,0,46,14,0,60,30,0,70,40,
+  0,86,55,0,97,68,6,113,82,25,122,93,43,136,105,61,148,119,77,162,131,91,
+  174,143,100,188,156,113,201,169,127,217,186,0,26,0,0,36,0,0,48,0,0,61,0,
+  0,72,0,0,86,21,19,99,32,34,114,47,46,122,56,57,137,66,78,148,79,88,163,
+  89,102,173,106,111,188,120,124,201,132,137,214,145,3,25,0,5,35,0,0,47,0,
+  2,61,0,5,71,0,23,86,0,39,98,0,52,112,16,63,121,25,76,134,40,94,147,47,105,
+  161,64,119,173,73,126,187,92,140,199,106,155,217,119,0,20,0,0,31,0,7,42,
+  0,15,58,0,36,67,0,43,82,0,62,94,0,74,108,0,85,116,0,98,130,11,112,143,32,
+  126,156,45,137,168,59,148,182,72,164,194,89,177,210,99
+};
+
+static byte Murray[] =
+{
+  0,0,0,16,17,20,30,37,32,49,56,47,66,69,64,85,87,83,103,106,99,120,123,119,
+  132,135,130,152,155,150,165,168,163,186,189,185,199,201,193,221,223,219,
+  236,239,235,255,255,255,50,0,0,67,7,0,82,26,0,102,44,0,117,59,0,135,80,
+  0,153,96,11,166,116,36,183,126,42,202,140,67,218,159,79,235,181,92,252,
+  196,112,255,213,132,255,232,153,255,251,162,66,0,0,77,0,0,100,9,0,115,30,
+  7,130,43,16,150,63,37,169,80,59,173,93,60,199,109,85,213,130,99,235,148,
+  120,255,162,142,255,179,155,255,199,170,255,213,192,255,232,208,76,0,3,
+  83,0,9,105,0,29,123,19,46,139,33,66,155,50,79,172,66,99,192,86,107,198,
+  99,140,223,116,146,236,138,165,255,150,186,255,166,205,255,185,223,255,
+  203,238,255,219,252,66,0,49,77,0,62,99,0,83,119,10,102,130,24,112,146,44,
+  130,166,63,153,185,79,166,198,92,179,215,107,201,231,125,209,251,142,234,
+  255,162,255,255,181,255,255,195,255,255,213,255,49,0,89,62,0,102,83,0,119,
+  102,7,136,112,26,149,132,43,182,155,60,186,169,79,209,183,90,222,196,109,
+  242,221,129,255,236,146,255,254,165,255,255,179,255,255,196,255,255,212,
+  255,26,0,115,40,0,135,63,0,146,77,16,166,93,32,185,106,52,199,129,70,219,
+  148,86,239,159,99,254,176,117,255,193,133,255,208,150,255,228,168,255,244,
+  188,255,255,205,255,255,225,255,0,0,125,17,0,139,33,10,163,52,30,181,66,
+  44,192,86,64,212,103,82,229,120,96,248,130,107,255,152,128,255,166,149,
+  255,182,165,255,201,179,255,222,198,255,239,215,255,255,239,255,0,0,115,
+  0,7,135,3,26,148,23,43,169,36,62,185,57,76,208,72,93,212,97,112,239,105,
+  129,244,122,146,255,138,160,255,153,176,255,173,198,255,186,215,255,209,
+  231,255,228,249,255,0,10,89,0,24,99,0,47,123,3,64,143,14,74,158,36,97,176,
+  49,113,192,67,133,208,82,143,219,102,158,236,119,181,255,135,196,255,149,
+  211,255,168,234,255,186,248,255,201,255,255,0,27,43,0,42,56,0,57,82,0,83,
+  102,0,92,115,17,112,135,34,129,149,46,150,160,69,159,183,85,175,196,99,
+  192,218,119,215,226,136,231,254,152,249,255,168,255,255,185,255,255,0,36,
+  3,0,53,13,0,72,24,0,90,50,0,106,64,11,126,87,29,142,100,46,163,112,63,172,
+  132,79,188,145,95,203,163,115,223,183,133,241,198,152,255,218,162,255,236,
+  186,255,255,0,46,0,0,59,0,0,80,0,0,100,1,3,110,14,13,132,32,39,149,52,57,
+  166,73,64,179,77,80,198,92,97,212,113,120,229,136,132,248,149,159,255,175,
+  172,255,182,183,255,203,0,44,0,0,63,0,0,76,0,1,97,0,19,115,0,36,128,0,53,
+  149,10,70,163,32,82,178,42,102,201,49,117,211,79,136,226,96,153,248,109,
+  168,255,125,186,255,143,206,255,162,0,39,0,0,56,0,6,73,0,24,95,0,36,105,
+  0,56,125,0,77,145,0,92,160,0,103,172,16,129,189,34,142,205,46,158,226,66,
+  173,239,85,196,255,100,206,255,110,231,255,139,0,26,0,16,42,0,33,59,0,50,
+  79,0,66,93,0,87,109,0,103,129,0,115,146,0,132,160,1,149,181,26,170,196,
+  39,185,212,57,208,232,80,225,249,89,238,255,107,255,255,126
+};
+
+// pointer array positions must match palette numbers in header file
+static const byte *c64dtv_palettes_pointers[] =
+{
+  Spiff,
+  Murray,
+
+  NULL
+};
+
+// return c64 color with index.
+GdColor gd_c64_color(int index)
+{
+  return (GD_COLOR_TYPE_C64 << 24) + index;
+}
+
+// return atari color with index.
+GdColor gd_atari_color(int index)
+{
+  return (GD_COLOR_TYPE_ATARI << 24) + index;
+}
+
+GdColor gd_atari_color_huesat(int hue, int sat)
+{
+  return gd_atari_color(16 * hue + sat);
+}
+
+// return c64dtv color with index.
+GdColor gd_c64dtv_color(int index)
+{
+  return (GD_COLOR_TYPE_C64DTV << 24) + index;
+}
+
+GdColor gd_c64dtv_color_huesat(int hue, int sat)
+{
+  return gd_c64dtv_color(16 * hue + sat);
+}
+
+// return "unknown color"
+static GdColor unknown_color(void)
+{
+  return (GD_COLOR_TYPE_UNKNOWN << 24);
+}
+
+// convert color to rgbcolor; using the current palette.
+GdColor gd_color_get_rgb(GdColor color)
+{
+  int index;
+  const unsigned char *atari_pal;
+  const unsigned char *c64dtv_pal;
+  const GdColor *c64_pal;
+
+  switch (color >> 24)
+  {
+    case GD_COLOR_TYPE_RGB:
+      // is already rgb
+      return color;
+
+    case GD_COLOR_TYPE_C64:
+      if (setup.bd_palette_c64 < 0 ||
+         setup.bd_palette_c64 >= ARRAY_SIZE(c64_palettes_pointers) - 1)
+       setup.bd_palette_c64 = 0;       // silently switch to default, if invalid value
+      c64_pal = c64_palettes_pointers[setup.bd_palette_c64];
+      index = color & 0x0f;
+      return c64_pal[index];
+
+    case GD_COLOR_TYPE_C64DTV:
+      if (setup.bd_palette_c64dtv < 0 ||
+         setup.bd_palette_c64dtv >= ARRAY_SIZE(c64dtv_palettes_pointers) - 1)
+       setup.bd_palette_c64dtv = 0;    // silently switch to default, if invalid value
+      c64dtv_pal = c64dtv_palettes_pointers[setup.bd_palette_c64dtv];
+      index = color & 0xff;
+      return gd_color_get_from_rgb(c64dtv_pal[index * 3],
+                                  c64dtv_pal[index * 3 + 1],
+                                  c64dtv_pal[index * 3 + 2]);
+
+    case GD_COLOR_TYPE_ATARI:
+      if (setup.bd_palette_atari < 0 ||
+         setup.bd_palette_atari >= ARRAY_SIZE(atari_palettes_pointers) - 1)
+       setup.bd_palette_atari = 0;     // silently switch to default, if invalid value
+      atari_pal = atari_palettes_pointers[setup.bd_palette_atari];
+      index = color & 0xff;
+      return gd_color_get_from_rgb(atari_pal[index * 3],
+                                  atari_pal[index * 3 + 1],
+                                  atari_pal[index * 3 + 2]);
+
+    default:
+      return 0;        // (never reached)
+  }
+}
+
+unsigned int gd_color_get_r(GdColor color)
+{
+  return ((gd_color_get_rgb(color) >> 16) & 0xff);
+}
+
+unsigned int gd_color_get_g(GdColor color)
+{
+  return ((gd_color_get_rgb(color) >> 8) & 0xff);
+}
+
+unsigned int gd_color_get_b(GdColor color)
+{
+  return ((gd_color_get_rgb(color) >> 0) & 0xff);
+}
+
+// make up GdColor from r,g,b values.
+GdColor gd_color_get_from_rgb(int r, int g, int b)
+{
+  return (GD_COLOR_TYPE_RGB << 24) + (r << 16) + (g << 8) + b;
+}
+
+// make up GdColor from h,s,v values.
+// h=0..360, s=0..1, v=0..1
+GdColor gd_color_get_from_hsv(double h, double s, double v)
+{
+  int hi = (int)(h / 60) % 6;
+  double f = h / 60 - (int)(h / 60);    // fractional part
+  double p = v * (1 - s);
+  double q = v * (1 - f * s);
+  double t = v * (1 - (1 - f) * s);
+
+  v *= 255;
+  p *= 255;
+  q *= 255;
+  t *= 255;
+
+  switch(hi)
+  {
+    case 0: return gd_color_get_from_rgb(v, t, p);
+    case 1: return gd_color_get_from_rgb(q, v, p);
+    case 2: return gd_color_get_from_rgb(p, v, t);
+    case 3: return gd_color_get_from_rgb(p, q, v);
+    case 4: return gd_color_get_from_rgb(t, p, v);
+    case 5: return gd_color_get_from_rgb(v, p, q);
+  }
+
+  // no way we reach this
+  return gd_color_get_from_rgb(0, 0, 0);
+}
+
+
+GdColor gd_color_get_from_string(const char *color)
+{
+  int i, r, g, b;
+
+  for (i = 0; i < ARRAY_SIZE(c64_color_names); i++)
+    if (strEqualCase(color, c64_color_names[i]))
+      return gd_c64_color(i);
+
+  // we do not use sscanf(color, "atari..." as may be lowercase
+  if (strEqualCaseN(color, "Atari", strlen("Atari")))
+  {
+    const char *b = color + strlen("Atari");
+    int c;
+
+    if (sscanf(b, "%02x", &c) == 1)
+      return gd_atari_color(c);
+
+    Warn("Unknown Atari color: %s", color);
+
+    return unknown_color();
+  }
+
+  // we do not use sscanf(color, "c64dtv..." as may be lowercase
+  if (strEqualCaseN(color, "C64DTV", strlen("C64DTV")))
+  {
+    const char *b = color + strlen("C64DTV");
+    int c;
+
+    if (sscanf(b, "%02x", &c) == 1)
+      return gd_c64dtv_color(c);
+
+    Warn("Unknown C64DTV color: %s", color);
+
+    return unknown_color();
+  }
+
+  // may or may not have a #
+  if (color[0] == '#')
+    color++;
+
+  if (sscanf(color, "%02x%02x%02x", &r, &g, &b) != 3)
+  {
+    i = gd_random_int_range(0, 16);
+
+    Warn("Unkonwn color %s", color);
+
+    return unknown_color();
+  }
+
+  return gd_color_get_from_rgb(r, g, b);
+}
+
+const char *gd_color_get_string(GdColor color)
+{
+  static char text[16];
+
+  if (gd_color_is_c64(color))
+  {
+    return c64_color_names[color & 0xff];
+  }
+
+  if (gd_color_is_atari(color))
+  {
+    sprintf(text, "Atari%02x", color & 0xff);
+    return text;
+  }
+
+  if (gd_color_is_dtv(color))
+  {
+    sprintf(text, "C64DTV%02x", color & 0xff);
+    return text;
+  }
+
+  sprintf(text, "#%02x%02x%02x", (color >> 16) & 255, (color >> 8) & 255, color & 255);
+  return text;
+}
+
+boolean gd_color_is_c64(GdColor color)
+{
+  return (color >> 24) == GD_COLOR_TYPE_C64;
+}
+
+boolean gd_color_is_atari(GdColor color)
+{
+    return (color >> 24) == GD_COLOR_TYPE_ATARI;
+}
+
+boolean gd_color_is_dtv(GdColor color)
+{
+    return (color >> 24) == GD_COLOR_TYPE_C64DTV;
+}
+
+boolean gd_color_is_unknown(GdColor color)
+{
+  return (color >> 24) == GD_COLOR_TYPE_UNKNOWN;
+}
+
+GdColor gd_gdash_color(int c)
+{
+  // these values are taken from the title screen, drawn by cws.
+  // so menus and everything else will look nice!
+  // the 16 colors that can be used are the same as on c64.
+  // "Black", "White", "Red", "Cyan", "Purple", "Green", "Blue", "Yellow",
+  // "Orange", "Brown", "LightRed", "Gray1", "Gray2", "LightGreen", "LightBlue", "Gray3",
+  // not in the png: cyan, purple. gray3 is darker in the png.
+  // 17th color is the player's leg in the png. i not connected it to any c64
+  // color, but it is used for theme images for example.
+  const GdColor gdash_colors[] =
+  {
+    0x000000, 0xffffff, 0xe33939, 0x55aaaa, 0xaa55aa, 0x71aa55, 0x0039ff, 0xffff55,
+    0xe37139, 0xaa7139, 0xe09080, 0x555555, 0x717171, 0xc6e38e, 0xaaaaff, 0x8e8e8e,
+
+    0x5555aa,
+  };
+
+  return gdash_colors[c];
+}
diff --git a/src/game_bd/bd_colors.h b/src/game_bd/bd_colors.h
new file mode 100644 (file)
index 0000000..15f1e36
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_COLORS_H
+#define BD_COLORS_H
+
+
+typedef unsigned int GdColor;
+
+/* color internal:
+   XXRRGGBB;
+   XX is 0 for RGB,
+         1 for c64 colors (bb=index)
+         3 for c64dtv (bb=index)
+         2 for atari colors (bb=index)
+*/
+
+typedef enum _color_type
+{
+  GD_COLOR_TYPE_RGB    = 0,
+  GD_COLOR_TYPE_C64    = 1,
+  GD_COLOR_TYPE_C64DTV = 2,
+  GD_COLOR_TYPE_ATARI  = 3,
+
+  GD_COLOR_TYPE_UNKNOWN         // should be the last one
+} GdColorType;
+
+#define GD_DEFAULT_COLOR_TYPE                  GD_COLOR_TYPE_RGB
+
+// traditional c64 color indexes.
+#define GD_COLOR_INDEX_BLACK                   0
+#define GD_COLOR_INDEX_WHITE                   1
+#define GD_COLOR_INDEX_RED                     2
+#define GD_COLOR_INDEX_CYAN                    3
+#define GD_COLOR_INDEX_PURPLE                  4
+#define GD_COLOR_INDEX_GREEN                   5
+#define GD_COLOR_INDEX_BLUE                    6
+#define GD_COLOR_INDEX_YELLOW                  7
+#define GD_COLOR_INDEX_ORANGE                  8
+#define GD_COLOR_INDEX_BROWN                   9
+#define GD_COLOR_INDEX_LIGHTRED                        10
+#define GD_COLOR_INDEX_GRAY1                   11
+#define GD_COLOR_INDEX_GRAY2                   12
+#define GD_COLOR_INDEX_LIGHTGREEN              13
+#define GD_COLOR_INDEX_LIGHTBLUE               14
+#define GD_COLOR_INDEX_GRAY3                   15
+
+#define GD_GDASH_BLACK                         gd_gdash_color(GD_COLOR_INDEX_BLACK)
+#define GD_GDASH_WHITE                         gd_gdash_color(GD_COLOR_INDEX_WHITE)
+#define GD_GDASH_RED                           gd_gdash_color(GD_COLOR_INDEX_RED)
+#define GD_GDASH_CYAN                          gd_gdash_color(GD_COLOR_INDEX_CYAN)
+#define GD_GDASH_PURPLE                                gd_gdash_color(GD_COLOR_INDEX_PURPLE)
+#define GD_GDASH_GREEN                         gd_gdash_color(GD_COLOR_INDEX_GREEN)
+#define GD_GDASH_BLUE                          gd_gdash_color(GD_COLOR_INDEX_BLUE)
+#define GD_GDASH_YELLOW                                gd_gdash_color(GD_COLOR_INDEX_YELLOW)
+#define GD_GDASH_ORANGE                                gd_gdash_color(GD_COLOR_INDEX_ORANGE)
+#define GD_GDASH_BROWN                         gd_gdash_color(GD_COLOR_INDEX_BROWN)
+#define GD_GDASH_LIGHTRED                      gd_gdash_color(GD_COLOR_INDEX_LIGHTRED)
+#define GD_GDASH_GRAY1                         gd_gdash_color(GD_COLOR_INDEX_GRAY1)
+#define GD_GDASH_GRAY2                         gd_gdash_color(GD_COLOR_INDEX_GRAY2)
+#define GD_GDASH_LIGHTGREEN                    gd_gdash_color(GD_COLOR_INDEX_LIGHTGREEN)
+#define GD_GDASH_LIGHTBLUE                     gd_gdash_color(GD_COLOR_INDEX_LIGHTBLUE)
+#define GD_GDASH_GRAY3                         gd_gdash_color(GD_COLOR_INDEX_GRAY3)
+
+#define GD_GDASH_MIDDLEBLUE                    gd_gdash_color(16)
+
+#define GD_COLOR_INVALID                       0xFFFFFFFF
+
+#define GD_C64_COLOR(index)                    ((GD_COLOR_TYPE_C64 << 24) + (index))
+
+// palette numbers must match pointer array positions in source file
+#define GD_PALETTE_C64_VICE_NEW                        0
+#define GD_PALETTE_C64_VICE_OLD                        1
+#define GD_PALETTE_C64_VIDE_DEFAULT            2
+#define GD_PALETTE_C64_C64HQ                   3
+#define GD_PALETTE_C64_C64S                    4
+#define GD_PALETTE_C64_CCS64                   5
+#define GD_PALETTE_C64_FRODO                   6
+#define GD_PALETTE_C64_GODOT                   7
+#define GD_PALETTE_C64_PC64                    8
+#define GD_PALETTE_C64_RTADASH                 9
+
+#define GD_DEFAULT_PALETTE_C64                 GD_PALETTE_C64_VICE_NEW
+
+// palette numbers must match pointer array positions in source file
+#define GD_PALETTE_C64DTV_SPIFF                        0
+#define GD_PALETTE_C64DTV_MURRAY               1
+
+#define GD_DEFAULT_PALETTE_C64DTV              GD_PALETTE_C64DTV_SPIFF
+
+// palette numbers must match pointer array positions in source file
+#define GD_PALETTE_ATARI_BUILTIN               0
+#define GD_PALETTE_ATARI_BUILTIN_CONTRAST      1
+#define GD_PALETTE_ATARI_DEFAULT               2
+#define GD_PALETTE_ATARI_JAKUB                 3
+#define GD_PALETTE_ATARI_JAKUB_CONTRAST                4
+#define GD_PALETTE_ATARI_REAL                  5
+#define GD_PALETTE_ATARI_REAL_CONTRAST         6
+#define GD_PALETTE_ATARI_XFORMER               7
+
+#define GD_DEFAULT_PALETTE_ATARI               GD_PALETTE_ATARI_BUILTIN
+
+
+// color
+GdColor gd_c64_color(int index);
+GdColor gd_atari_color(int index);
+GdColor gd_c64dtv_color(int index);
+
+GdColor gd_atari_color_huesat(int hue, int sat);
+GdColor gd_c64dtv_color_huesat(int hue, int sat);
+
+unsigned int gd_color_get_r(GdColor color);
+unsigned int gd_color_get_g(GdColor color);
+unsigned int gd_color_get_b(GdColor color);
+
+GdColor gd_color_get_rgb(GdColor color);
+GdColor gd_color_get_from_rgb(int r, int g, int b);
+GdColor gd_color_get_from_hsv(double h, double s, double v);
+GdColor gd_color_get_from_string(const char *color);
+const char *gd_color_get_string(GdColor color);
+
+boolean gd_color_is_c64(GdColor color);
+boolean gd_color_is_atari(GdColor color);
+boolean gd_color_is_dtv(GdColor color);
+boolean gd_color_is_unknown(GdColor color);
+
+GdColor gd_gdash_color(int c);
+
+#endif // BD_COLORS_H
diff --git a/src/game_bd/bd_elements.h b/src/game_bd/bd_elements.h
new file mode 100644 (file)
index 0000000..dd36b1e
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_ELEMENTS_H
+#define BD_ELEMENTS_H
+
+
+// These are the objects in caves.
+typedef enum _element
+{
+  O_SPACE,
+  O_DIRT,
+  O_DIRT_SLOPED_UP_RIGHT,
+  O_DIRT_SLOPED_UP_LEFT,
+  O_DIRT_SLOPED_DOWN_LEFT,
+  O_DIRT_SLOPED_DOWN_RIGHT,
+  O_DIRT_BALL,
+  O_DIRT_BALL_F,
+  O_DIRT_LOOSE,
+  O_DIRT_LOOSE_F,
+  O_DIRT2,
+  O_BRICK,
+  O_BRICK_SLOPED_UP_RIGHT,
+  O_BRICK_SLOPED_UP_LEFT,
+  O_BRICK_SLOPED_DOWN_LEFT,
+  O_BRICK_SLOPED_DOWN_RIGHT,
+  O_BRICK_NON_SLOPED,
+  O_MAGIC_WALL,
+  O_PRE_OUTBOX,
+  O_OUTBOX,
+  O_PRE_INVIS_OUTBOX,
+  O_INVIS_OUTBOX,
+  O_STEEL,
+  O_STEEL_SLOPED_UP_RIGHT,
+  O_STEEL_SLOPED_UP_LEFT,
+  O_STEEL_SLOPED_DOWN_LEFT,
+  O_STEEL_SLOPED_DOWN_RIGHT,
+  O_STEEL_EXPLODABLE,
+  O_STEEL_EATABLE,
+  O_BRICK_EATABLE,
+  O_STONE,
+  O_STONE_F,
+  O_FLYING_STONE,
+  O_FLYING_STONE_F,
+  O_MEGA_STONE,
+  O_MEGA_STONE_F,
+  O_DIAMOND,
+  O_DIAMOND_F,
+  O_FLYING_DIAMOND,
+  O_FLYING_DIAMOND_F,
+  O_NUT,
+  O_NUT_F,
+  O_BLADDER_SPENDER,
+  O_INBOX,
+  O_H_EXPANDING_WALL,
+  O_V_EXPANDING_WALL,
+  O_EXPANDING_WALL,
+  O_H_EXPANDING_STEEL_WALL,
+  O_V_EXPANDING_STEEL_WALL,
+  O_EXPANDING_STEEL_WALL,
+  O_EXPANDING_WALL_SWITCH,
+  O_CREATURE_SWITCH,
+  O_BITER_SWITCH,
+  O_REPLICATOR_SWITCH,
+  O_CONVEYOR_SWITCH,
+  O_CONVEYOR_DIR_SWITCH,
+  O_ACID,
+  O_FALLING_WALL,
+  O_FALLING_WALL_F,
+  O_BOX,
+  O_TIME_PENALTY,
+  O_GRAVESTONE,
+  O_STONE_GLUED,
+  O_DIAMOND_GLUED,
+  O_DIAMOND_KEY,
+  O_TRAPPED_DIAMOND,
+  O_CLOCK,
+  O_DIRT_GLUED,
+  O_KEY_1,
+  O_KEY_2,
+  O_KEY_3,
+  O_DOOR_1,
+  O_DOOR_2,
+  O_DOOR_3,
+
+  O_POT,
+  O_GRAVITY_SWITCH,
+  O_PNEUMATIC_HAMMER,
+  O_TELEPORTER,
+  O_SKELETON,
+  O_WATER,
+  O_WATER_1,
+  O_WATER_2,
+  O_WATER_3,
+  O_WATER_4,
+  O_WATER_5,
+  O_WATER_6,
+  O_WATER_7,
+  O_WATER_8,
+  O_WATER_9,
+  O_WATER_10,
+  O_WATER_11,
+  O_WATER_12,
+  O_WATER_13,
+  O_WATER_14,
+  O_WATER_15,
+  O_WATER_16,
+  O_COW_1,
+  O_COW_2,
+  O_COW_3,
+  O_COW_4,
+  O_COW_ENCLOSED_1,
+  O_COW_ENCLOSED_2,
+  O_COW_ENCLOSED_3,
+  O_COW_ENCLOSED_4,
+  O_COW_ENCLOSED_5,
+  O_COW_ENCLOSED_6,
+  O_COW_ENCLOSED_7,
+  O_WALLED_DIAMOND,
+  O_WALLED_KEY_1,
+  O_WALLED_KEY_2,
+  O_WALLED_KEY_3,
+
+  O_AMOEBA,
+  O_AMOEBA_2,
+  O_REPLICATOR,
+  O_CONVEYOR_LEFT,
+  O_CONVEYOR_RIGHT,
+  O_LAVA,
+  O_SWEET,
+  O_VOODOO,
+  O_SLIME,
+  O_BLADDER,
+  O_BLADDER_1,
+  O_BLADDER_2,
+  O_BLADDER_3,
+  O_BLADDER_4,
+  O_BLADDER_5,
+  O_BLADDER_6,
+  O_BLADDER_7,
+  O_BLADDER_8,
+
+  O_WAITING_STONE,
+  O_CHASING_STONE,
+  O_GHOST,
+  O_FIREFLY_1,
+  O_FIREFLY_2,
+  O_FIREFLY_3,
+  O_FIREFLY_4,
+  O_ALT_FIREFLY_1,
+  O_ALT_FIREFLY_2,
+  O_ALT_FIREFLY_3,
+  O_ALT_FIREFLY_4,
+  O_BUTTER_1,
+  O_BUTTER_2,
+  O_BUTTER_3,
+  O_BUTTER_4,
+  O_ALT_BUTTER_1,
+  O_ALT_BUTTER_2,
+  O_ALT_BUTTER_3,
+  O_ALT_BUTTER_4,
+  O_STONEFLY_1,
+  O_STONEFLY_2,
+  O_STONEFLY_3,
+  O_STONEFLY_4,
+  O_BITER_1,
+  O_BITER_2,
+  O_BITER_3,
+  O_BITER_4,
+  O_DRAGONFLY_1,
+  O_DRAGONFLY_2,
+  O_DRAGONFLY_3,
+  O_DRAGONFLY_4,
+
+  O_PRE_PL_1,
+  O_PRE_PL_2,
+  O_PRE_PL_3,
+  O_PLAYER,
+  O_PLAYER_BOMB,
+  O_PLAYER_ROCKET_LAUNCHER,
+  O_PLAYER_GLUED,
+  O_PLAYER_STIRRING,
+
+  O_ROCKET_LAUNCHER,
+  O_ROCKET_1,
+  O_ROCKET_2,
+  O_ROCKET_3,
+  O_ROCKET_4,
+
+  O_BOMB,
+  O_BOMB_TICK_1,
+  O_BOMB_TICK_2,
+  O_BOMB_TICK_3,
+  O_BOMB_TICK_4,
+  O_BOMB_TICK_5,
+  O_BOMB_TICK_6,
+  O_BOMB_TICK_7,
+
+  O_NITRO_PACK,
+  O_NITRO_PACK_F,
+  O_NITRO_PACK_EXPLODE,
+
+  O_PRE_CLOCK_1,
+  O_PRE_CLOCK_2,
+  O_PRE_CLOCK_3,
+  O_PRE_CLOCK_4,
+  O_PRE_DIA_1,
+  O_PRE_DIA_2,
+  O_PRE_DIA_3,
+  O_PRE_DIA_4,
+  O_PRE_DIA_5,
+  O_EXPLODE_1,
+  O_EXPLODE_2,
+  O_EXPLODE_3,
+  O_EXPLODE_4,
+  O_EXPLODE_5,
+  O_PRE_STONE_1,
+  O_PRE_STONE_2,
+  O_PRE_STONE_3,
+  O_PRE_STONE_4,
+  O_PRE_STEEL_1,
+  O_PRE_STEEL_2,
+  O_PRE_STEEL_3,
+  O_PRE_STEEL_4,
+  O_GHOST_EXPL_1,
+  O_GHOST_EXPL_2,
+  O_GHOST_EXPL_3,
+  O_GHOST_EXPL_4,
+  O_BOMB_EXPL_1,
+  O_BOMB_EXPL_2,
+  O_BOMB_EXPL_3,
+  O_BOMB_EXPL_4,
+  O_NITRO_EXPL_1,
+  O_NITRO_EXPL_2,
+  O_NITRO_EXPL_3,
+  O_NITRO_EXPL_4,
+  O_AMOEBA_2_EXPL_1,
+  O_AMOEBA_2_EXPL_2,
+  O_AMOEBA_2_EXPL_3,
+  O_AMOEBA_2_EXPL_4,
+  O_NUT_EXPL_1,
+  O_NUT_EXPL_2,
+  O_NUT_EXPL_3,
+  O_NUT_EXPL_4,
+
+  // these are used internally for the pneumatic hammer, and should not be used in the editor!
+  // (not even as an effect destination or something like that)
+  O_PLAYER_PNEUMATIC_LEFT,
+  O_PLAYER_PNEUMATIC_RIGHT,
+  O_PNEUMATIC_ACTIVE_LEFT,
+  O_PNEUMATIC_ACTIVE_RIGHT,
+
+  O_UNKNOWN,   // unknown element imported or read from bdcff
+  O_NONE,      // do not draw this element when creating cave; can be used,
+               // for example, to skip drawing a maze's path
+
+  O_MAX,       // remembering last index: this should get an integer value
+               // which is 1 more than the one above.
+
+  // fake elements to help drawing
+  O_FAKE_BONUS,
+  O_INBOX_CLOSED,
+  O_INBOX_OPEN,
+  O_OUTBOX_CLOSED,
+  O_OUTBOX_OPEN,
+  O_COVERED,
+  O_PLAYER_LEFT,
+  O_PLAYER_RIGHT,
+  O_PLAYER_UP,
+  O_PLAYER_DOWN,
+  O_PLAYER_TAP,
+  O_PLAYER_BLINK,
+  O_PLAYER_TAP_BLINK,
+  O_PLAYER_PUSH_LEFT,
+  O_PLAYER_PUSH_RIGHT,
+  O_CREATURE_SWITCH_ON,
+  O_EXPANDING_WALL_SWITCH_HORIZ,
+  O_EXPANDING_WALL_SWITCH_VERT,
+  O_GRAVITY_SWITCH_ACTIVE,
+  O_REPLICATOR_SWITCH_ON,
+  O_REPLICATOR_SWITCH_OFF,
+  O_CONVEYOR_DIR_NORMAL,
+  O_CONVEYOR_DIR_CHANGED,
+  O_CONVEYOR_SWITCH_OFF,
+  O_CONVEYOR_SWITCH_ON,
+
+  O_MAGIC_WALL_ACTIVE,
+  O_REPLICATOR_ACTIVE,
+  O_CONVEYOR_LEFT_ACTIVE,
+  O_CONVEYOR_RIGHT_ACTIVE,
+  O_BITER_SWITCH_1,
+  O_BITER_SWITCH_2,
+  O_BITER_SWITCH_3,
+  O_BITER_SWITCH_4,
+
+  O_QUESTION_MARK,
+  O_EATABLE,
+  O_DOWN_ARROW,
+  O_LEFTRIGHT_ARROW,
+  O_EVERYDIR_ARROW,
+  O_GLUED,
+  O_OUT,
+  O_EXCLAMATION_MARK,
+
+  O_MAX_ALL,
+
+  SCANNED = 0x100,
+  COVERED = 0x200,
+  SKIPPED = 0x400,
+
+  // binary AND this to elements to get rid of properties above.
+  O_MASK = ~(SCANNED | COVERED | SKIPPED)
+} GdElement;
+
+typedef enum _sound
+{
+  GD_S_NONE,
+
+  GD_S_STONE_PUSHING,
+  GD_S_STONE_FALLING,
+  GD_S_STONE_IMPACT,
+  GD_S_MEGA_STONE_PUSHING,
+  GD_S_MEGA_STONE_FALLING,
+  GD_S_MEGA_STONE_IMPACT,
+  GD_S_FLYING_STONE_PUSHING,
+  GD_S_FLYING_STONE_FALLING,
+  GD_S_FLYING_STONE_IMPACT,
+  GD_S_WAITING_STONE_PUSHING,
+  GD_S_CHASING_STONE_PUSHING,
+  GD_S_NUT_PUSHING,
+  GD_S_NUT_FALLING,
+  GD_S_NUT_IMPACT,
+  GD_S_NUT_CRACKING,
+  GD_S_DIRT_BALL_FALLING,
+  GD_S_DIRT_BALL_IMPACT,
+  GD_S_DIRT_LOOSE_FALLING,
+  GD_S_DIRT_LOOSE_IMPACT,
+  GD_S_NITRO_PACK_PUSHING,
+  GD_S_NITRO_PACK_FALLING,
+  GD_S_NITRO_PACK_IMPACT,
+  GD_S_FALLING_WALL_FALLING,
+  GD_S_FALLING_WALL_IMPACT,
+  GD_S_EXPANDING_WALL,
+  GD_S_WALL_REAPPEARING,
+  GD_S_DIAMOND_FALLING_RANDOM,         // randomly select a diamond falling sound
+  GD_S_DIAMOND_FALLING_1,
+  GD_S_DIAMOND_FALLING_2,
+  GD_S_DIAMOND_FALLING_3,
+  GD_S_DIAMOND_FALLING_4,
+  GD_S_DIAMOND_FALLING_5,
+  GD_S_DIAMOND_FALLING_6,
+  GD_S_DIAMOND_FALLING_7,
+  GD_S_DIAMOND_FALLING_8,
+  GD_S_DIAMOND_IMPACT_RANDOM,          // randomly select a diamond impact sound
+  GD_S_DIAMOND_IMPACT_1,
+  GD_S_DIAMOND_IMPACT_2,
+  GD_S_DIAMOND_IMPACT_3,
+  GD_S_DIAMOND_IMPACT_4,
+  GD_S_DIAMOND_IMPACT_5,
+  GD_S_DIAMOND_IMPACT_6,
+  GD_S_DIAMOND_IMPACT_7,
+  GD_S_DIAMOND_IMPACT_8,
+  GD_S_FLYING_DIAMOND_FALLING_RANDOM,  // randomly select a flying diamond falling sound
+  GD_S_FLYING_DIAMOND_FALLING_1,
+  GD_S_FLYING_DIAMOND_FALLING_2,
+  GD_S_FLYING_DIAMOND_FALLING_3,
+  GD_S_FLYING_DIAMOND_FALLING_4,
+  GD_S_FLYING_DIAMOND_FALLING_5,
+  GD_S_FLYING_DIAMOND_FALLING_6,
+  GD_S_FLYING_DIAMOND_FALLING_7,
+  GD_S_FLYING_DIAMOND_FALLING_8,
+  GD_S_FLYING_DIAMOND_IMPACT_RANDOM,   // randomly select a flying diamond impact sound
+  GD_S_FLYING_DIAMOND_IMPACT_1,
+  GD_S_FLYING_DIAMOND_IMPACT_2,
+  GD_S_FLYING_DIAMOND_IMPACT_3,
+  GD_S_FLYING_DIAMOND_IMPACT_4,
+  GD_S_FLYING_DIAMOND_IMPACT_5,
+  GD_S_FLYING_DIAMOND_IMPACT_6,
+  GD_S_FLYING_DIAMOND_IMPACT_7,
+  GD_S_FLYING_DIAMOND_IMPACT_8,
+  GD_S_DIAMOND_COLLECTING,
+  GD_S_FLYING_DIAMOND_COLLECTING,
+  GD_S_SKELETON_COLLECTING,
+  GD_S_PNEUMATIC_COLLECTING,
+  GD_S_BOMB_COLLECTING,
+  GD_S_CLOCK_COLLECTING,
+  GD_S_SWEET_COLLECTING,
+  GD_S_KEY_COLLECTING,
+  GD_S_DIAMOND_KEY_COLLECTING,
+  GD_S_SLIME,
+  GD_S_LAVA,
+  GD_S_REPLICATOR,
+  GD_S_ACID_SPREADING,
+  GD_S_BLADDER_MOVING,
+  GD_S_BLADDER_PUSHING,
+  GD_S_BLADDER_CONVERTING,
+  GD_S_BLADDER_SPENDER,
+  GD_S_BITER_EATING,
+
+  GD_S_DOOR_OPENING,
+  GD_S_DIRT_WALKING,
+  GD_S_EMPTY_WALKING,
+  GD_S_STIRRING,
+  GD_S_BOX_PUSHING,
+  GD_S_TELEPORTER,
+  GD_S_TIMEOUT_10,
+  GD_S_TIMEOUT_9,
+  GD_S_TIMEOUT_8,
+  GD_S_TIMEOUT_7,
+  GD_S_TIMEOUT_6,
+  GD_S_TIMEOUT_5,
+  GD_S_TIMEOUT_4,
+  GD_S_TIMEOUT_3,
+  GD_S_TIMEOUT_2,
+  GD_S_TIMEOUT_1,
+  GD_S_TIMEOUT_0,
+  GD_S_EXPLODING,
+  GD_S_BOMB_EXPLODING,
+  GD_S_GHOST_EXPLODING,
+  GD_S_VOODOO_EXPLODING,
+  GD_S_NITRO_PACK_EXPLODING,
+  GD_S_BOMB_PLACING,
+  GD_S_FINISHED,               // loop
+  GD_S_SWITCH_BITER,
+  GD_S_SWITCH_CREATURES,
+  GD_S_SWITCH_GRAVITY,
+  GD_S_SWITCH_EXPANDING,
+  GD_S_SWITCH_CONVEYOR,
+  GD_S_SWITCH_REPLICATOR,
+
+  GD_S_AMOEBA,                 // loop
+  GD_S_AMOEBA_MAGIC,           // loop
+  GD_S_MAGIC_WALL,             // loop
+  GD_S_COVERING,               // loop
+  GD_S_PNEUMATIC_HAMMER,       // loop
+  GD_S_WATER,                  // loop
+
+  GD_S_CRACKING,
+  GD_S_GRAVITY_CHANGING,
+  GD_S_BONUS_LIFE,
+
+  GD_S_MAX,
+} GdSound;
+
+#endif // BD_ELEMENTS_H
diff --git a/src/game_bd/bd_gameplay.c b/src/game_bd/bd_gameplay.c
new file mode 100644 (file)
index 0000000..12eb53b
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+void gd_game_free(GdGame *game)
+{
+  // stop sounds
+  gd_sound_off();
+
+  if (game->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->gfx_buffer)
+    gd_cave_map_free(game->gfx_buffer);
+
+  game->player_lives = 0;
+
+  if (game->cave)
+    gd_cave_free(game->cave);
+
+  free(game);
+}
+
+// add bonus life. if sound enabled, play sound, too.
+static void add_bonus_life(GdGame *game, boolean inform_user)
+{
+  if (inform_user)
+  {
+    gd_sound_play_bonus_life();
+    game->bonus_life_flash = 100;
+  }
+
+  // really increment number of lifes? only in a real game, nowhere else.
+  if (game->player_lives &&
+      game->player_lives < gd_caveset_data->maximum_lives)
+  {
+    // only add a life, if lives is > 0.
+    // lives == 0 is a test run or a snapshot, no bonus life then.
+    // also, obey max number of bonus lives.
+    game->player_lives++;
+  }
+}
+
+// increment score of player.
+// flash screen if bonus life
+static void increment_score(GdGame *game, int increment)
+{
+  int i;
+
+  i = game->player_score / gd_caveset_data->bonus_life_score;
+  game->player_score += increment;
+  game->cave_score += increment;
+
+  // if score crossed bonus_life_score point boundary, player won a bonus life
+  if (game->player_score / gd_caveset_data->bonus_life_score > i)
+    add_bonus_life(game, TRUE);
+}
+
+// do the things associated with loading a new cave. function creates gfx buffer and the like.
+static void load_cave(GdGame *game)
+{
+  int x, y;
+
+  // delete element buffer
+  if (game->element_buffer)
+    gd_cave_map_free(game->element_buffer);
+  game->element_buffer = NULL;
+
+  // delete last element buffer
+  if (game->last_element_buffer)
+    gd_cave_map_free(game->last_element_buffer);
+  game->last_element_buffer = NULL;
+
+  // delete direction buffer
+  if (game->dir_buffer)
+    gd_cave_map_free(game->dir_buffer);
+  game->dir_buffer = NULL;
+
+  // delete gfx buffer
+  if (game->gfx_buffer)
+    gd_cave_map_free(game->gfx_buffer);
+  game->gfx_buffer = NULL;
+
+  // load the cave
+  game->cave_score = 0;
+
+  // delete previous cave
+  gd_cave_free(game->cave);
+
+  if (native_bd_level.loaded_from_caveset)
+    game->original_cave = gd_get_original_cave_from_caveset(game->cave_num);
+  else
+    game->original_cave = native_bd_level.cave;
+
+  game->cave = gd_get_prepared_cave(game->original_cave, game->level_num);
+
+  // if requested, recolor cave (cave is a copy only, so no worries)
+  if (setup.bd_random_colors)
+    gd_cave_set_random_colors(game->cave, setup.bd_default_color_type);
+
+  if (game->cave->intermission && game->cave->intermission_instantlife)
+    add_bonus_life(game, FALSE);
+
+  game->milliseconds_anim = 0;
+  game->milliseconds_game = 0;        // set game timer to zero, too
+
+  // create new element buffer
+  game->element_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->element_buffer[y][x] = O_NONE;
+
+  // create new last element buffer
+  game->last_element_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_element_buffer[y][x] = O_NONE;
+
+  // create new direction buffer
+  game->dir_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->dir_buffer[y][x] = GD_MV_STILL;
+
+  // create new gfx buffer
+  game->gfx_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->gfx_buffer[y][x] = -1;    // fill with "invalid"
+}
+
+GdCave *gd_create_snapshot(GdGame *game)
+{
+  GdCave *snapshot;
+
+  if (game->cave == NULL)
+    return NULL;
+
+  // make an exact copy
+  snapshot = gd_cave_new_from_cave(game->cave);
+
+  return snapshot;
+}
+
+// this starts a new game
+GdGame *gd_game_new(const int cave, const int level)
+{
+  GdGame *game;
+
+  game = checked_calloc(sizeof(GdGame));
+
+  game->cave_num = cave;
+  game->level_num = level;
+
+  game->player_lives = gd_caveset_data->initial_lives;
+  game->player_score = 0;
+
+  game->player_move = GD_MV_STILL;
+  game->player_move_stick = FALSE;
+  game->player_fire = FALSE;
+
+  game->state_counter = GAME_INT_LOAD_CAVE;
+
+  game->show_story = TRUE;
+
+  return game;
+}
+
+static void iterate_cave(GdGame *game, GdDirection player_move, boolean fire)
+{
+  boolean suicide = FALSE;
+
+  // ANYTHING EXCEPT A TIMEOUT, WE ITERATE THE CAVE
+  if (game->cave->player_state != GD_PL_TIMEOUT)
+  {
+    if (TapeIsPlaying_ReplayBD())
+    {
+      byte *action_rnd = TapePlayAction_BD();
+
+      if (action_rnd != NULL)
+      {
+       int action_bd = map_action_RND_to_BD(action_rnd[0]);
+
+       player_move = (action_bd & GD_REPLAY_MOVE_MASK);
+       fire        = (action_bd & GD_REPLAY_FIRE_MASK) != 0;
+      }
+    }
+
+    // iterate cave
+    gd_cave_iterate(game->cave, player_move, fire, suicide);
+
+    if (game->cave->score)
+      increment_score(game, game->cave->score);
+
+    gd_sound_play_cave(game->cave);
+  }
+
+  if (game->cave->player_state == GD_PL_EXITED)
+  {
+    if (game->cave->intermission &&
+       game->cave->intermission_rewardlife &&
+       game->player_lives != 0)
+    {
+      // one life extra for completing intermission
+      add_bonus_life(game, FALSE);
+    }
+
+    // start adding points for remaining time
+    game->state_counter = GAME_INT_CHECK_BONUS_TIME;
+    gd_cave_clear_sounds(game->cave);
+
+    // play cave finished sound
+    gd_sound_play(game->cave, GD_S_FINISHED, O_NONE, -1, -1);
+    gd_sound_play_cave(game->cave);
+  }
+
+  if (game->cave->player_state == GD_PL_DIED ||
+      game->cave->player_state == GD_PL_TIMEOUT)
+  {
+    game_bd.game_over = TRUE;
+    game_bd.cover_screen = TRUE;
+  }
+}
+
+static GdGameState gd_game_main_int(GdGame *game, boolean allow_iterate, boolean fast_forward)
+{
+  int millisecs_elapsed = 20;
+  boolean frame;    // set to true, if this will be an animation frame
+  GdGameState return_state;
+  int counter_next;
+  int x, y;
+
+  counter_next = GAME_INT_INVALID;
+  return_state = GD_GAME_INVALID_STATE;
+  game->milliseconds_anim += millisecs_elapsed;    // keep track of time
+  frame = FALSE;    // set to true, if this will be an animation frame
+
+  if (game->milliseconds_anim >= 40)
+  {
+    frame = TRUE;
+    game->milliseconds_anim -= 40;
+  }
+
+  // cannot be less than uncover start.
+  if (game->state_counter < GAME_INT_LOAD_CAVE)
+  {
+    ;
+  }
+  else if (game->state_counter == GAME_INT_LOAD_CAVE)
+  {
+    // do the things associated with loading a new cave. function creates gfx buffer and the like.
+    load_cave(game);
+
+    return_state = GD_GAME_NOTHING;
+    counter_next = GAME_INT_SHOW_STORY;
+  }
+  else if (game->state_counter == GAME_INT_SHOW_STORY)
+  {
+    // for normal game, every cave can have a long string of description/story. show that.
+
+    // if we have a story...
+#if 0
+    if (game->show_story && game->original_cave && game->original_cave->story != NULL)
+      Info("Cave Story: %s", game->original_cave->story);
+#endif
+
+    counter_next = GAME_INT_START_UNCOVER;
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter == GAME_INT_START_UNCOVER)
+  {
+    // the very beginning.
+
+    // cover all cells of cave
+    for (y = 0; y < game->cave->h; y++)
+      for (x = 0; x < game->cave->w; x++)
+       game->cave->map[y][x] |= COVERED;
+
+    counter_next = game->state_counter + 1;
+
+    // very important: tell the caller that we loaded a new cave.
+    // size of the cave might be new, colors might be new, and so on.
+    return_state = GD_GAME_CAVE_LOADED;
+  }
+  else if (game->state_counter < GAME_INT_UNCOVER_ALL)
+  {
+    // uncover animation
+
+    // to play cover sound
+    gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
+    gd_sound_play_cave(game->cave);
+
+    counter_next = game->state_counter;
+
+    if (frame)
+    {
+      int j;
+
+      // original game uncovered one cell per line each frame.
+      // we have different cave sizes, so uncover width * height / 40 random
+      // cells each frame. (original was width = 40).
+      // this way the uncovering is the same speed also for intermissions.
+      for (j = 0; j < game->cave->w * game->cave->h / 40; j++)
+      {
+       y = gd_random_int_range(0, game->cave->h);
+       x = gd_random_int_range(0, game->cave->w);
+
+       game->cave->map[y][x] &= ~COVERED;
+      }
+
+      counter_next++;    // as we did something, advance the counter.
+    }
+
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter == GAME_INT_UNCOVER_ALL)
+  {
+    // time to uncover the whole cave.
+    for (y = 0; y < game->cave->h; y++)
+      for (x = 0; x < game->cave->w; x++)
+       game->cave->map[y][x] &= ~COVERED;
+
+    // to stop uncover sound.
+    gd_cave_clear_sounds(game->cave);
+    gd_sound_play_cave(game->cave);
+
+    counter_next = GAME_INT_CAVE_RUNNING;
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter == GAME_INT_CAVE_RUNNING)
+  {
+    // normal.
+    int cavespeed;
+
+    if (!fast_forward)
+      cavespeed = game->cave->speed;   // cave speed in ms, like 175ms/frame
+    else
+      cavespeed = 40;    // if fast forward, ignore cave speed, and go as 25 iterations/sec
+
+    // ITERATION - cave is running.
+
+    // 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 (allow_iterate)
+      game->milliseconds_game += millisecs_elapsed;
+
+    // increment cycle (frame) counter for the current cave iteration
+    game->itercycle++;
+
+    if (game->milliseconds_game >= cavespeed)
+    {
+      GdPlayerState pl;
+
+      game->milliseconds_game -= cavespeed;
+      pl = game->cave->player_state;
+
+      // initialize buffers for last cave element and direction for next iteration
+      for (y = 0; y < game->cave->h; y++)
+      {
+       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;
+       }
+      }
+
+      // store last maximum number of cycles (to force redraw if changed)
+      game->itermax_last = game->itermax;
+
+      // update maximum number of cycles (frame) per cave iteration
+      game->itermax = game->itercycle;
+
+      // reset cycle (frame) counter for the next cave iteration
+      game->itercycle = 0;
+
+      iterate_cave(game, game->player_move, game->player_fire);
+
+      if (game->player_move == GD_MV_STILL)
+      {
+       game->player_move_stick = FALSE;
+      }
+      else
+      {
+       game->player_move_stick = TRUE;
+       game->player_move = GD_MV_STILL;
+      }
+
+      // as we iterated, the score and the like could have been changed.
+      return_state = GD_GAME_LABELS_CHANGED;
+
+      // and if the cave timeouted at this moment, that is a special case.
+      if (pl != GD_PL_TIMEOUT && game->cave->player_state == GD_PL_TIMEOUT)
+       return_state = GD_GAME_TIMEOUT_NOW;
+    }
+
+    // do not change counter state, as it is set by iterate_cave()
+    counter_next = game->state_counter;
+  }
+  else if (game->state_counter == GAME_INT_CHECK_BONUS_TIME)
+  {
+    // before covering, we check for time bonus score
+    if (frame)
+    {
+      // if time remaining, bonus points are added. do not start animation yet.
+      if (game->cave->time > 0)
+      {
+        // subtract number of "milliseconds" - nothing to do with gameplay->millisecs!
+       game->cave->time -= game->cave->timing_factor;
+
+       // higher levels get more bonus points per second remained
+       increment_score(game, game->cave->timevalue);
+
+       // if much time (> 60s) remained, fast counter :)
+       if (game->cave->time > 60 * game->cave->timing_factor)
+       {
+         // decrement by nine each frame, so it also looks like a fast counter. 9 is 8 + 1!
+         game->cave->time -= 8 * game->cave->timing_factor;
+         increment_score(game, game->cave->timevalue * 8);
+       }
+
+       // just to be neat
+       if (game->cave->time < 0)
+         game->cave->time = 0;
+
+       counter_next = game->state_counter;    // do not change yet
+      }
+      else
+      {
+       game_bd.level_solved = TRUE;
+       game_bd.cover_screen = TRUE;
+
+       // if no more points, start waiting a bit, and later start covering.
+       counter_next = GAME_INT_WAIT_BEFORE_COVER;
+      }
+
+      if (game->cave->time / game->cave->timing_factor > 8)
+       gd_sound_play(game->cave, GD_S_FINISHED, O_NONE, -1, -1); // play cave finished sound
+
+      // play bonus sound
+      gd_cave_set_seconds_sound(game->cave);
+      gd_sound_play_cave(game->cave);
+
+      return_state = GD_GAME_LABELS_CHANGED;
+    }
+    else
+    {
+      return_state = GD_GAME_NOTHING;
+
+      // do not change counter state, as it is set by iterate_cave()
+      counter_next = game->state_counter;
+    }
+  }
+  else if (game->state_counter == GAME_INT_WAIT_BEFORE_COVER)
+  {
+    // after adding bonus points, we wait some time before starting to cover.
+    // this is the FIRST frame... so we check for game over and maybe jump there
+    // if no more lives, game is over.
+    counter_next = game->state_counter;
+
+    if (game->player_lives == 0)
+      return_state = GD_GAME_NO_MORE_LIVES;
+    else
+      return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter > GAME_INT_WAIT_BEFORE_COVER &&
+          game->state_counter < GAME_INT_COVER_START)
+  {
+    // after adding bonus points, we wait some time before starting to cover.
+    // ... and the other frames.
+    counter_next = game->state_counter;
+    if (frame)
+      counter_next++;    // 40 ms elapsed, advance counter
+
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter == GAME_INT_COVER_START)
+  {
+    // starting to cover. start cover sound.
+
+    gd_cave_clear_sounds(game->cave);
+    gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
+
+    // to play cover sound
+    gd_sound_play_cave(game->cave);
+
+    counter_next = game->state_counter + 1;
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter > GAME_INT_COVER_START &&
+          game->state_counter < GAME_INT_COVER_ALL)
+  {
+    // covering.
+    gd_sound_play(game->cave, GD_S_COVERING, O_COVERED, -1, -1);
+
+    counter_next = game->state_counter;
+
+    if (frame)
+    {
+      int j;
+
+      counter_next++;    // 40 ms elapsed, doing cover: advance counter
+
+      // covering eight times faster than uncovering.
+      for (j = 0; j < game->cave->w * game->cave->h * 8 / 40; j++)
+       game->cave->map[gd_random_int_range(0, game->cave->h)][gd_random_int_range (0, game->cave->w)] |= COVERED;
+    }
+
+    return_state = GD_GAME_NOTHING;
+  }
+  else if (game->state_counter == GAME_INT_COVER_ALL)
+  {
+    // cover all
+    for (y = 0; y < game->cave->h; y++)
+      for (x = 0; x < game->cave->w; x++)
+       game->cave->map[y][x] |= COVERED;
+
+    counter_next = game->state_counter + 1;
+    return_state = GD_GAME_NOTHING;
+
+    // to stop uncover sound.
+    gd_cave_clear_sounds(game->cave);
+    gd_sound_play_cave(game->cave);
+  }
+  else
+  {
+    // cover all + 1
+
+    if (game->player_lives != 0)
+      return_state = GD_GAME_NOTHING;    // and go to next level
+    else
+      return_state = GD_GAME_GAME_OVER;
+  }
+
+  // draw the cave
+  if (frame)
+  {
+    if (game->bonus_life_flash)    // bonus life - frames
+      game->bonus_life_flash--;
+
+    game->animcycle = (game->animcycle + 1) % 8;
+  }
+
+  // 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,
+                    game->bonus_life_flash != 0, game->animcycle, setup.bd_show_invisible_outbox);
+
+  game->state_counter = counter_next;
+
+  return return_state;
+}
+
+void play_game_func(GdGame *game, int action)
+{
+  GdGameState state;
+  boolean move_up    = ((action & JOY_UP)    != 0);
+  boolean move_down  = ((action & JOY_DOWN)  != 0);
+  boolean move_left  = ((action & JOY_LEFT)  != 0);
+  boolean move_right = ((action & JOY_RIGHT) != 0);
+  boolean fire  = ((action & (JOY_BUTTON_1 | JOY_BUTTON_2)) != 0);
+
+  if (game->player_move_stick || move_up || move_down || move_left || move_right) // no "fire"!
+  {
+    // get movement
+    game->player_move = gd_direction_from_keypress(move_up, move_down, move_left, move_right);
+
+    // when storing last action, only update fire action with direction
+    // (prevents clearing direction if snapping stopped before action is performed)
+    game->player_fire = fire;
+  }
+
+  // if no direction was stored before, allow setting fire to current state
+  if (game->player_move == GD_MV_STILL)
+    game->player_fire = fire;
+
+  // tell the interrupt "20ms has passed"
+  state = gd_game_main_int(game, !game->out_of_window, FALSE);
+
+  // state of game, returned by gd_game_main_int
+  switch (state)
+  {
+    case GD_GAME_CAVE_LOADED:
+      // scroll to start position
+      gd_scroll_to_origin();
+
+      // fill whole screen with black - cave might be smaller than previous!
+      FillRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE, BLACK_PIXEL);
+      break;
+
+    default:
+      break;
+  }
+
+  // for the sdl version, it seems nicer if we first scroll, and then draw.
+  // scrolling for the sdl version will merely invalidate the whole gfx buffer.
+  // 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 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
+    game->out_of_window = gd_scroll(game, game->cave->player_state == GD_PL_NOT_YET, FALSE);
+  }
+}
diff --git a/src/game_bd/bd_gameplay.h b/src/game_bd/bd_gameplay.h
new file mode 100644 (file)
index 0000000..aa9a48d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_GAMEPLAY_H
+#define BD_GAMEPLAY_H
+
+#include "bd_cave.h"
+
+
+#define GAME_INT_INVALID               -100
+
+// prepare cave, gfx buffer
+#define GAME_INT_LOAD_CAVE             -73
+
+// show description/note of cave.
+#define GAME_INT_SHOW_STORY            -72
+
+// waiting fire button after showing the story.
+#define GAME_INT_SHOW_STORY_WAIT       -71
+
+// start uncovering
+#define GAME_INT_START_UNCOVER         -70
+
+// ...70 frames until full uncover...
+#define GAME_INT_UNCOVER_ALL           -1
+
+// normal running state.
+#define GAME_INT_CAVE_RUNNING          0
+
+// add points for remaining time
+#define GAME_INT_CHECK_BONUS_TIME      1
+
+// ...2..99 = wait and do nothing, after adding time
+#define GAME_INT_WAIT_BEFORE_COVER     2
+
+// start covering
+#define GAME_INT_COVER_START           100
+
+// ... 8 frames of cover animation
+#define GAME_INT_COVER_ALL             108
+
+
+typedef struct _gd_game
+{
+  GdString player_name;         // Name of player
+  int player_score;             // Score of player
+  int player_lives;             // Remaining lives of player
+
+  GdDirection player_move;
+  boolean player_move_stick;
+  boolean player_fire;
+
+  GdCave *cave;                 // Copy of the cave. This is the iterated, changed (ruined...) one
+  GdCave *original_cave;        // original cave from caveset. used to record highscore
+
+  boolean out_of_window;        // will be set to true, if player is not visible in the window,
+                                // and we have to wait for scrolling
+
+  int cave_num;                 // actual playing cave number
+  int cave_score;               // score collected in this cave
+  int level_num;                // actual playing level
+  int bonus_life_flash;         // different kind of flashing, for bonus life
+
+  int state_counter;            // counter used to control the game flow, rendering of caves
+  int **element_buffer;
+  int **last_element_buffer;
+  int **dir_buffer;
+  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 animcycle;
+  int milliseconds_game;
+  int milliseconds_anim;
+
+  int replay_no_more_movements;
+  boolean show_story;          // to remember that story for a particular cave was already shown.
+} GdGame;
+
+typedef enum _gd_game_state
+{
+  GD_GAME_INVALID_STATE,
+  GD_GAME_SHOW_STORY,
+  GD_GAME_SHOW_STORY_WAIT,
+  GD_GAME_CAVE_LOADED,
+  GD_GAME_NOTHING,
+  GD_GAME_LABELS_CHANGED,
+  GD_GAME_TIMEOUT_NOW,          // this signals the moment of time out
+  GD_GAME_NO_MORE_LIVES,
+  GD_GAME_STOP,
+  GD_GAME_GAME_OVER,
+} GdGameState;
+
+GdCave *gd_create_snapshot(GdGame *gameplay);
+
+void gd_game_free(GdGame *gameplay);
+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);
+
+void play_game_func(GdGame *game, int action);
+
+#endif // BD_GAMEPLAY_H
diff --git a/src/game_bd/bd_graphics.c b/src/game_bd/bd_graphics.c
new file mode 100644 (file)
index 0000000..aa091ba
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+// !!! (can be removed later) !!!
+#define DO_GFX_SANITY_CHECK    TRUE
+
+// distance to screen edge in cells when scrolling the screen
+#define SCROLL_EDGE_DISTANCE   4
+
+// these can't be larger than 31, or they mess up utf8 coding or are the same as some ascii letter
+#define GD_DOWN_CHAR           1
+#define GD_LEFT_CHAR           2
+#define GD_UP_CHAR             3
+#define GD_RIGHT_CHAR          4
+
+#define GD_BALL_CHAR           5
+#define GD_UNCHECKED_BOX_CHAR  6
+#define GD_CHECKED_BOX_CHAR    7
+
+#define GD_PLAYER_CHAR         8
+#define GD_DIAMOND_CHAR                9
+#define GD_SKELETON_CHAR       11
+#define GD_KEY_CHAR            12
+#define GD_COMMENT_CHAR                13
+
+// pointer to tile bitmap (which may be prepared with level-specific colors)
+static Bitmap *gd_tile_bitmap = NULL;
+// pointer to reference tile bitmap (without level-specific colors)
+static Bitmap *gd_tile_bitmap_reference = NULL;
+
+// optional title screen bitmaps (foreground and background)
+static Bitmap *gd_title_screen_bitmaps[2] = { NULL, NULL };
+
+// screen area
+Bitmap *gd_screen_bitmap = NULL;
+
+static int play_area_w = 0;
+static int play_area_h = 0;
+
+static int scroll_x, scroll_y;
+
+// quit, global variable which is set to true if the application should quit
+boolean gd_quit = FALSE;
+
+static int cell_size = 0;
+
+// graphic info for game objects/frames and players/actions/frames
+struct GraphicInfo_BD graphic_info_bd_object[O_MAX_ALL][8];
+// graphic info for game graphics template for level-specific colors
+struct GraphicInfo_BD graphic_info_bd_color_template;
+
+static inline int c64_png_colors(int r, int g, int b, int a)
+{
+  static const int c64_png_cols[] =
+  {
+    // ABGR
+
+    /* 0000 */ 0,      // transparent
+    /* 0001 */ 0,
+    /* 0010 */ 0,
+    /* 0011 */ 0,
+    /* 0100 */ 0,
+    /* 0101 */ 0,
+    /* 0110 */ 0,
+    /* 0111 */ 0,
+    /* 1000 */ 1,      // black - background
+    /* 1001 */ 2,      // red - foreg1
+    /* 1010 */ 5,      // green - amoeba
+    /* 1011 */ 4,      // yellow - foreg3
+    /* 1100 */ 6,      // blue - slime
+    /* 1101 */ 3,      // purple - foreg2
+    /* 1110 */ 7,      // black around arrows (used in editor) is coded as cyan
+    /* 1111 */ 8,      // white is the arrow
+  };
+
+  int c = ((a >> 7) * 8 +
+          (b >> 7) * 4 +
+          (g >> 7) * 2 +
+          (r >> 7) * 1);
+
+  return c64_png_cols[c];
+}
+
+void set_cell_size(int s)
+{
+  cell_size = s;
+}
+
+void set_play_area(int w, int h)
+{
+  play_area_w = w;
+  play_area_h = h;
+}
+
+void gd_init_play_area(void)
+{
+  set_play_area(SXSIZE, SYSIZE);
+}
+
+/*
+  logical_size: logical pixel size of playfield, usually larger than the screen.
+  physical_size: visible part. (remember: player_x-x1!)
+
+  center: the coordinates to scroll to.
+  exact: scroll exactly
+  start: start scrolling if difference is larger than
+  to: scroll to, if started, until difference is smaller than
+  current
+
+  desired: the function stores its data here
+  speed: the function stores its data here
+
+  cell_size: size of one cell. used to determine if the play field is only a
+  slightly larger than the screen, in that case no scrolling is desirable
+*/
+static boolean cave_scroll(int logical_size, int physical_size, int center, boolean exact,
+                          int *current, int *desired, int speed)
+{
+  int max = MAX(0, logical_size - physical_size);
+  int edge_distance = SCROLL_EDGE_DISTANCE;
+  int cell_size = TILESIZE_VAR;
+  boolean changed = FALSE;
+
+  // start scrolling when player reaches certain distance to screen edge
+  int start = physical_size / 2 - cell_size * edge_distance;
+
+  // scroll so that the player is at the center; the allowed difference is this
+  int to = cell_size;
+
+  // if cave size smaller than the screen, no scrolling req'd
+  if (logical_size < physical_size)
+  {
+    *desired = 0;
+
+    if (*current != 0)
+    {
+      *current = 0;
+      changed = TRUE;
+    }
+
+    return changed;
+  }
+
+  if (logical_size <= physical_size + cell_size)
+  {
+    // if cave size is only a slightly larger than the screen, also no scrolling
+    // scroll to the middle of the cell
+    *desired = max / 2;
+  }
+  else
+  {
+    if (exact)
+    {
+      // if exact scrolling, just go exactly to the center.
+      *desired = center;
+    }
+    else
+    {
+      // hystheresis function.
+      // when scrolling left, always go a bit less left than player being at the middle.
+      // when scrolling right, always go a bit less to the right.
+      if (*current < center - start)
+       *desired = center - to;
+      if (*current > center + start)
+       *desired = center + to;
+    }
+  }
+
+  *desired = MIN(MAX(0, *desired), max);
+
+  if (*current < *desired)
+  {
+    *current = MIN(*current + speed, *desired);
+
+    changed = TRUE;
+  }
+
+  if (*current > *desired)
+  {
+    *current = MAX(*current - speed, *desired);
+
+    changed = TRUE;
+  }
+
+  return changed;
+}
+
+// just set current viewport to upper left.
+void gd_scroll_to_origin(void)
+{
+  scroll_x = 0;
+  scroll_y = 0;
+}
+
+int get_scroll_x(void)
+{
+  return scroll_x / cell_size;
+}
+
+int get_scroll_y(void)
+{
+  return scroll_y / cell_size;
+}
+
+int get_play_area_w(void)
+{
+  return play_area_w / cell_size;
+}
+
+int get_play_area_h(void)
+{
+  return play_area_h / cell_size;
+}
+
+static boolean player_out_of_window(GdGame *game, int player_x, int player_y)
+{
+  // if not yet born, we treat as visible. so cave will run.
+  // the user is unable to control an unborn player, so this is the right behaviour.
+  if (game->cave->player_state == GD_PL_NOT_YET)
+    return FALSE;
+
+  // check if active player is outside drawing area. if yes, we should wait for scrolling
+  if ((player_x * cell_size) < scroll_x ||
+      (player_x * cell_size + cell_size - 1) > scroll_x + play_area_w)
+  {
+    // but only do the wait, if the player SHOULD BE visible, ie. he is inside
+    // the defined visible area of the cave
+    if (game->cave->player_x >= game->cave->x1 &&
+       game->cave->player_x <= game->cave->x2)
+      return TRUE;
+  }
+
+  if ((player_y * cell_size) < scroll_y ||
+      (player_y * cell_size + cell_size - 1) > scroll_y + play_area_h)
+  {
+    // but only do the wait, if the player SHOULD BE visible, ie. he is inside
+    // the defined visible area of the cave
+    if (game->cave->player_y >= game->cave->y1 &&
+       game->cave->player_y <= game->cave->y2)
+      return TRUE;
+  }
+
+  // player is inside visible window
+  return FALSE;
+}
+
+/*
+  SCROLLING
+  
+  scrolls to the player during game play.
+  called by drawcave
+  returns true, if player is not visible-ie it is out of the visible size in the drawing area.
+*/
+boolean gd_scroll(GdGame *game, boolean exact_scroll, boolean immediate)
+{
+  static int scroll_desired_x = 0, scroll_desired_y = 0;
+  static int scroll_speed_last = -1;
+  int player_x, player_y, visible_x, visible_y;
+  boolean changed;
+
+  // max scrolling speed depends on the speed of the cave.
+  // game moves cell_size_game * 1s / cave time pixels in a second.
+  // scrolling moves scroll speed * 1s / scroll_time in a second.
+  // these should be almost equal; scrolling speed a little slower.
+  // that way, the player might reach the border with a small probability,
+  // but the scrolling will not "oscillate", ie. turn on for little intervals as it has
+  // caught up with the desired position. smaller is better.
+  int scroll_speed = cell_size * 20 / game->cave->speed;
+
+  if (!setup.bd_scroll_delay)
+    exact_scroll = TRUE;
+
+  if (immediate)
+    scroll_speed = cell_size * MAX(game->cave->w, game->cave->h);
+
+  player_x = game->cave->player_x - game->cave->x1; // cell coordinates of player
+  player_y = game->cave->player_y - game->cave->y1;
+
+  // if player is outside visible playfield area, use faster scrolling
+  // (might happen when wrapping around the playfield, teleporting etc.)
+  if (player_out_of_window(game, player_x, player_y))
+    scroll_speed *= 4;
+
+  // if scrolling started with player outside visible playfield area, keep faster scrolling
+  if (scroll_speed_last > scroll_speed)
+    scroll_speed = scroll_speed_last;
+
+  // store current (potentially faster) scrolling speed for next time
+  scroll_speed_last = scroll_speed;
+
+  // pixel size of visible part of the cave (may be smaller in intermissions)
+  visible_x = (game->cave->x2 - game->cave->x1 + 1) * cell_size;
+  visible_y = (game->cave->y2 - game->cave->y1 + 1) * cell_size;
+
+  // cell_size contains the scaled size, but we need the original.
+  changed = FALSE;
+
+  if (cave_scroll(visible_x, play_area_w, player_x * cell_size + cell_size / 2 - play_area_w / 2,
+                 exact_scroll, &scroll_x, &scroll_desired_x, scroll_speed))
+    changed = TRUE;
+
+  if (cave_scroll(visible_y, play_area_h, player_y * cell_size + cell_size / 2 - play_area_h / 2,
+                 exact_scroll, &scroll_y, &scroll_desired_y, scroll_speed))
+    changed = TRUE;
+
+  // if scrolling, we should update entire screen.
+  if (changed)
+  {
+    int x, y;
+
+    for (y = 0; y < game->cave->h; y++)
+      for (x = 0; x < game->cave->w; x++)
+       game->gfx_buffer[y][x] |= GD_REDRAW;
+  }
+
+  // if no scrolling required, reset last (potentially faster) scrolling speed
+  if (!changed)
+    scroll_speed_last = -1;
+
+  // check if active player is visible at the moment.
+  return player_out_of_window(game, player_x, player_y);
+}
+
+// returns true, if the given surface seems to be a c64 imported image.
+static boolean surface_has_c64_colors(SDL_Surface *surface)
+{
+  boolean has_c64_colors = TRUE;       // default: assume C64 colors
+  const unsigned char *p;
+  int x, y;
+
+  if (surface->format->BytesPerPixel != 4)
+    return FALSE;
+
+  SDL_LockSurface(surface);
+
+  for (y = 0; y < surface->h && has_c64_colors; y++)
+  {
+    p = ((unsigned char *)surface->pixels) + y * surface->pitch;
+
+    for (x = 0; x < surface->w * surface->format->BytesPerPixel && has_c64_colors; x++)
+      if (p[x] != 0 && p[x] != 255)
+       has_c64_colors = FALSE;
+  }
+
+  SDL_UnlockSurface(surface);
+
+  return has_c64_colors;
+}
+
+// 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)
+{
+  if (surface->format->BytesPerPixel != 1)
+    return;
+
+  SDL_Color c;
+
+  c.r = gd_color_get_r(col);
+  c.g = gd_color_get_g(col);
+  c.b = gd_color_get_b(col);
+
+  SDL_SetPaletteColors(surface->format->palette, &c, index, 1);
+}
+
+// takes a c64_gfx.png-coded 32-bit surface, and creates a paletted surface in our internal format.
+static SDL_Surface *get_tile_surface_c64(SDL_Surface *surface, int scale_down_factor)
+{
+  static SDL_Surface *tile_surface_c64 = NULL;
+  static unsigned char *pixels = NULL;
+  int width  = surface->w;
+  int height = surface->h;
+  int out = 0;
+  int x, y;
+
+  if (!surface_has_c64_colors(surface))
+    return NULL;
+
+  if (surface->format->BytesPerPixel != 4)
+    Fail("C64 style surface has wrong color depth -- should not happen");
+
+  if (tile_surface_c64 != NULL)
+    SDL_FreeSurface(tile_surface_c64);
+
+  checked_free(pixels);
+
+  pixels = checked_malloc(width * height);
+
+  SDL_LockSurface(surface);
+
+  for (y = 0; y < height; y++)
+  {
+    unsigned int *p = (unsigned int *)((char *)surface->pixels + y * surface->pitch);
+
+    for (x = 0; x < width; x++)
+    {
+      int r = (p[x] & surface->format->Rmask) >> surface->format->Rshift << surface->format->Rloss;
+      int g = (p[x] & surface->format->Gmask) >> surface->format->Gshift << surface->format->Gloss;
+      int b = (p[x] & surface->format->Bmask) >> surface->format->Bshift << surface->format->Bloss;
+      // should be:
+      // a = (p[x]&surface->format->Amask) >> surface->format->Ashift << surface->format->Aloss;
+      // but we do not use the alpha channel in sdash, so we just use 255 (max alpha)
+
+      pixels[out++] = c64_png_colors(r, g, b, 255);
+    }
+  }
+
+  SDL_UnlockSurface(surface);
+
+  // create new surface from pixel data
+  tile_surface_c64 =
+    SDL_CreateRGBSurfaceFrom((void *)pixels, width, height, 8, width, 0, 0, 0, 0);
+
+  if (tile_surface_c64 == NULL)
+    Fail("SDL_CreateRGBSurfaceFrom() failed: %s", SDL_GetError());
+
+  if (scale_down_factor > 1)
+  {
+    SDL_Surface *surface_old = tile_surface_c64;
+    int width_scaled  = width  / scale_down_factor;
+    int height_scaled = height / scale_down_factor;
+
+    // replace surface with scaled-down variant
+    tile_surface_c64 = SDLZoomSurface(surface_old, width_scaled, height_scaled);
+
+    // free previous (non-scaled) surface
+    SDL_FreeSurface(surface_old);
+  }
+
+  return tile_surface_c64;
+}
+
+static Bitmap *get_tile_bitmap_c64(GdCave *cave, SDL_Surface *surface)
+{
+  static Bitmap *tile_bitmap_c64 = NULL;
+
+  if (surface == NULL)
+    return NULL;
+
+  if (tile_bitmap_c64 != NULL)
+    FreeBitmap(tile_bitmap_c64);
+
+  // set surface color palette to cave colors
+  set_surface_palette_color(surface, 0, 0);
+  set_surface_palette_color(surface, 1, gd_color_get_rgb(cave->color0));
+  set_surface_palette_color(surface, 2, gd_color_get_rgb(cave->color1));
+  set_surface_palette_color(surface, 3, gd_color_get_rgb(cave->color2));
+  set_surface_palette_color(surface, 4, gd_color_get_rgb(cave->color3));
+  set_surface_palette_color(surface, 5, gd_color_get_rgb(cave->color4));
+  set_surface_palette_color(surface, 6, gd_color_get_rgb(cave->color5));
+  set_surface_palette_color(surface, 7, 0);
+  set_surface_palette_color(surface, 8, 0);
+
+  // create bitmap from C64 surface
+  tile_bitmap_c64 = SDLGetBitmapFromSurface(surface);
+
+  return tile_bitmap_c64;
+}
+
+void gd_prepare_tile_bitmap(GdCave *cave, Bitmap *bitmap, int scale_down_factor)
+{
+  static SDL_Surface *tile_surface_c64 = NULL;
+  static Bitmap *gd_tile_bitmap_original = NULL;
+  static int scale_down_factor_last = -1;
+
+  if (program.headless)
+    return;
+
+  // check if tile bitmap has changed (different artwork or tile size selected)
+  if (bitmap != gd_tile_bitmap_original || scale_down_factor != scale_down_factor_last)
+  {
+    // check if tile bitmap has limited C64 style colors
+    tile_surface_c64 = get_tile_surface_c64(bitmap->surface, scale_down_factor);
+
+    // store original tile bitmap from current artwork set and scaling factor
+    gd_tile_bitmap_original = bitmap;
+    scale_down_factor_last = scale_down_factor;
+
+    // store reference tile bitmap from current artwork set (may be changed later)
+    gd_tile_bitmap_reference = bitmap;
+  }
+
+  // check if tile bitmap should be colored for next game
+  if (tile_surface_c64 != NULL)
+  {
+    // set tile bitmap to bitmap with level-specific colors
+    gd_tile_bitmap = get_tile_bitmap_c64(cave, tile_surface_c64);
+  }
+  else
+  {
+    // no special tile bitmap available for this artwork set
+    gd_tile_bitmap = NULL;
+  }
+}
+
+void gd_set_tile_bitmap_reference(Bitmap *bitmap)
+{
+  gd_tile_bitmap_reference = bitmap;
+}
+
+Bitmap *gd_get_tile_bitmap(Bitmap *bitmap)
+{
+  // if no special tile bitmap available, keep using default tile bitmap
+  if (gd_tile_bitmap == NULL)
+    return bitmap;
+
+  // if default bitmap refers to tile bitmap, use special tile bitmap
+  if (bitmap == gd_tile_bitmap_reference)
+    return gd_tile_bitmap;
+
+  return bitmap;
+}
+
+// returns true if the element is a player
+static inline boolean el_player(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_PLAYER) != 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;
+}
+
+#if 0
+// returns true if the element is collectible
+static inline boolean el_collectible(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_COLLECTIBLE) != 0;
+}
+#endif
+
+// returns true if the element is pushable
+static inline boolean el_pushable(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_PUSHABLE) != 0;
+}
+
+// returns true if the element can move
+static inline boolean el_can_move(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_CAN_MOVE) != 0;
+}
+
+// returns true if the element can fall
+static inline boolean el_falling(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_FALLING) != 0;
+}
+
+// returns true if the element is growing
+static inline boolean el_growing(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_GROWING) != 0;
+}
+
+// returns true if the element is exploding
+static inline boolean el_explosion(const int element)
+{
+  return (gd_elements[element & O_MASK].properties & P_EXPLOSION) != 0;
+}
+
+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) =
+    (draw_masked ? BlitBitmapMasked : BlitBitmap);
+  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 tile = game->element_buffer[y][x];
+  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 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)
+  {
+    int dx = (dir == GD_MV_LEFT ? +1 : dir == GD_MV_RIGHT ? -1 : 0);
+    int dy = (dir == GD_MV_UP   ? +1 : dir == GD_MV_DOWN  ? -1 : 0);
+    int old_x = cave->getx(cave, x + dx, y + dy);
+    int old_y = cave->gety(cave, x + dx, y + dy);
+    int last_tile_from = game->last_element_buffer[old_y][old_x] & ~SKIPPED;
+    boolean old_is_player = el_player(last_tile_from);
+
+    // check special case of player running into enemy from top or left side
+    if (old_is_player)
+    {
+      game->element_buffer[y][x] = (dir == GD_MV_LEFT  ? O_PLAYER_LEFT  :
+                                    dir == GD_MV_RIGHT ? O_PLAYER_RIGHT :
+                                    dir == GD_MV_UP    ? O_PLAYER_UP    :
+                                    dir == GD_MV_DOWN  ? O_PLAYER_DOWN  : O_PLAYER);
+
+      // draw player running into explosion (else player would disappear immediately)
+      gd_drawcave_tile(dest, game, x, y, draw_masked);
+
+      game->element_buffer[y][x] = tile;
+    }
+
+    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;
+
+#if DO_GFX_SANITY_CHECK
+  if (use_native_bd_graphics_engine() && !setup.small_game_graphics && !program.headless)
+  {
+    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 new_y = g->src_y / g->height;
+
+    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,
+            new_x, new_y,
+            old_x, old_y,
+            gd_elements[tile].name);
+    }
+  }
+#endif
+
+  // if game element not moving (or no smooth movements requested), simply draw tile
+  if (!is_moving || !use_smooth_movements)
+  {
+    blit_bitmap(tile_bitmap, dest, g->src_x, g->src_y, cell_size, cell_size, sx, sy);
+
+    return;
+  }
+
+  // draw smooth animation for game element moving between two cave tiles
+
+  if (!(game->last_element_buffer[y][x] & SKIPPED))
+  {
+    // redraw previous game element on the cave field the new element is moving to
+    int tile_last = game->last_element_buffer[y][x];
+
+    // only redraw previous game element if it is diggable (like dirt etc.)
+    if (!el_diggable(tile_last))
+      tile_last = O_SPACE;
+
+    struct GraphicInfo_BD *g_old = &graphic_info_bd_object[tile_last][frame];
+    Bitmap *tile_bitmap_old = gd_get_tile_bitmap(g_old->bitmap);
+
+    blit_bitmap(tile_bitmap_old, dest, g_old->src_x, g_old->src_y, cell_size, cell_size, sx, sy);
+  }
+
+  // get cave field position the game element is moving from
+  int dx = (dir == GD_MV_LEFT ? +1 : dir == GD_MV_RIGHT ? -1 : 0);
+  int dy = (dir == GD_MV_UP   ? +1 : dir == GD_MV_DOWN  ? -1 : 0);
+  int old_x = cave->getx(cave, x + dx, y + dy);
+  int old_y = cave->gety(cave, x + dx, y + dy);
+  int tile_from = game->element_buffer[old_y][old_x] & ~SKIPPED;   // should never be skipped
+  struct GraphicInfo_BD *g_from = &graphic_info_bd_object[tile_from][frame];
+  Bitmap *tile_bitmap_from = gd_get_tile_bitmap(g_from->bitmap);
+  boolean old_is_player = el_player(tile_from);
+  boolean old_is_moving = (game->dir_buffer[old_y][old_x] != GD_MV_STILL);
+  boolean old_is_visible = (old_x >= cave->x1 &&
+                           old_x <= cave->x2 &&
+                           old_y >= cave->y1 &&
+                           old_y <= cave->y2);
+  if (old_is_visible)
+  {
+    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;
+    }
+  }
+
+  // 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);
+
+  // special case: redraw player snapping a game element
+  if (old_is_visible && old_is_player && !old_is_moving)
+  {
+    // redraw game element on the cave field the element is moving from
+    blit_bitmap(tile_bitmap_from, dest, g_from->src_x, g_from->src_y, cell_size, cell_size,
+               sx + dx * cell_size, sy + dy * cell_size);
+  }
+}
+
+int gd_drawcave(Bitmap *dest, GdGame *game, boolean force_redraw)
+{
+  GdCave *cave = game->cave;
+  static int show_flash_count = 0;
+  boolean show_flash = FALSE;
+  boolean draw_masked = FALSE;
+  boolean redraw_all = force_redraw;
+  int x, y;
+
+  // force redraw if maximum number of cycles has changed (to redraw moving elements)
+  if (game->itermax != game->itermax_last)
+    redraw_all = TRUE;
+
+  if (!cave->gate_open_flash)
+  {
+    show_flash_count = 0;
+  }
+  else
+  {
+    if (show_flash_count++ < 4)
+      show_flash = TRUE;
+
+    redraw_all = TRUE;
+  }
+
+  if (show_flash)
+  {
+    FillRectangle(dest, 0, 0, SXSIZE, SYSIZE, WHITE_PIXEL);
+
+    draw_masked = TRUE;
+    redraw_all = TRUE;
+  }
+
+  // here we draw all cells to be redrawn. we do not take scrolling area into
+  // consideration - sdl will do the clipping.
+  for (y = cave->y1; y <= cave->y2; y++)
+  {
+    for (x = cave->x1; x <= cave->x2; x++)
+    {
+      if (redraw_all ||
+         game->gfx_buffer[y][x] & GD_REDRAW ||
+         game->dir_buffer[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;
+
+       gd_drawcave_tile(dest, game, x, y, draw_masked);
+      }
+    }
+  }
+
+  return 0;
+}
+
+static SDL_Surface *get_surface_from_raw_data(const unsigned char *data, int size)
+{
+  SDL_RWops *rwop = SDL_RWFromConstMem(data, size);
+  SDL_Surface *surface = IMG_Load_RW(rwop, 1); // 1 = automatically closes rwop
+
+  return surface;
+}
+
+static SDL_Surface *get_surface_from_base64(const char *base64_data)
+{
+  int decoded_data_size = base64_decoded_size(base64_data);
+  unsigned char *decoded_data = checked_malloc(decoded_data_size);
+
+  base64_decode(decoded_data, base64_data);
+
+  SDL_Surface *surface = get_surface_from_raw_data(decoded_data, decoded_data_size);
+
+  checked_free(decoded_data);
+
+  return surface;
+}
+
+static SDL_Surface *get_title_screen_background_surface(SDL_Surface *tile)
+{
+  if (tile == NULL)
+    return NULL;
+
+  SDL_Surface *foreground_surface = gd_title_screen_bitmaps[0]->surface_masked;
+
+  // if foreground image has no transparency, no background image needed
+  if (foreground_surface->format->Amask == 0)
+    return NULL;
+
+  // use foreground image size for background image size
+  int w = foreground_surface->w;
+  int h = foreground_surface->h + tile->h;     // background is one scrolling tile higher
+
+  // create background surface
+  SDL_Surface *back = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
+  int x, y;
+
+  // fill background surface with tile
+  for (y = 0; y < h; y += tile->h)
+    for (x = 0; x < w; x += tile->w)
+      SDLBlitSurface(tile, back, 0, 0, tile->w, tile->h, x, y);
+
+  // background tile surface not needed anymore
+  SDL_FreeSurface(tile);
+
+  return back;
+}
+
+static SDL_Surface *get_title_screen_surface(int nr)
+{
+  if (gd_caveset_data == NULL)
+    return NULL;
+
+  // do not use title screen background without foreground image
+  if (nr == 1 && gd_title_screen_bitmaps[0] == NULL)
+    return NULL;
+
+  char *data = (nr == 0 ? gd_caveset_data->title_screen : gd_caveset_data->title_screen_scroll);
+
+  if (data == NULL)
+    return NULL;
+
+  SDL_Surface *surface = get_surface_from_base64(data);
+
+  if (surface == NULL)
+    return NULL;
+
+  return (nr == 0 ? surface : get_title_screen_background_surface(surface));
+}
+
+static void set_title_screen_bitmap(int nr)
+{
+  if (gd_title_screen_bitmaps[nr] != NULL)
+    FreeBitmap(gd_title_screen_bitmaps[nr]);
+
+  gd_title_screen_bitmaps[nr] = NULL;
+
+  SDL_Surface *surface = get_title_screen_surface(nr);
+
+  if (surface == NULL)
+    return;
+
+  int width_scaled  = surface->w * 2;
+  int height_scaled = surface->h * 2;
+  SDL_Surface *surface_scaled = SDLZoomSurface(surface, width_scaled, height_scaled);
+
+  gd_title_screen_bitmaps[nr] = SDLGetBitmapFromSurface(surface_scaled);
+
+  SDL_FreeSurface(surface);
+  SDL_FreeSurface(surface_scaled);
+}
+
+static void set_title_screen_bitmaps(void)
+{
+  int i;
+
+  for (i = 0; i < 2; i++)
+    set_title_screen_bitmap(i);
+}
+
+Bitmap **gd_get_title_screen_bitmaps(void)
+{
+  static char *levelset_subdir_last = NULL;
+
+  if (gd_caveset_data == NULL || gd_caveset_data->title_screen == NULL)
+    return NULL;
+
+  // check if stored cave set is used as current level set (may be outdated)
+  if (!strEqual(gd_caveset_data->levelset_subdir, leveldir_current->subdir))
+    return NULL;
+
+  // check if stored cave set has changed
+  if (!strEqual(gd_caveset_data->levelset_subdir, levelset_subdir_last))
+    set_title_screen_bitmaps();
+
+  setString(&levelset_subdir_last, gd_caveset_data->levelset_subdir);
+
+  return gd_title_screen_bitmaps;
+}
diff --git a/src/game_bd/bd_graphics.h b/src/game_bd/bd_graphics.h
new file mode 100644 (file)
index 0000000..6b522fc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_GRAPHICS_H
+#define BD_GRAPHICS_H
+
+#include "bd_cave.h"
+#include "bd_gameplay.h"
+
+
+extern Bitmap *gd_screen_bitmap;
+
+typedef unsigned int GdColor;
+
+void set_cell_size(int s);
+void set_play_area(int w, int h);
+
+int get_play_area_w(void);
+int get_play_area_h(void);
+
+void gd_init_play_area(void);
+
+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);
+
+int gd_drawcave(Bitmap *dest, GdGame *gameplay, boolean);
+boolean gd_scroll(GdGame *gameplay, boolean exact_scroll, boolean immediate);
+void gd_scroll_to_origin(void);
+int get_scroll_x(void);
+int get_scroll_y(void);
+
+Bitmap **gd_get_title_screen_bitmaps(void);
+
+#endif // BD_GRAPHICS_H
diff --git a/src/game_bd/bd_random.c b/src/game_bd/bd_random.c
new file mode 100644 (file)
index 0000000..b40ee4f
--- /dev/null
@@ -0,0 +1,583 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Originally developed and coded by Makoto Matsumoto and Takuji
+ * Nishimura.  Please mail <matumoto@math.keio.ac.jp>, if you're using
+ * code from this file in your own programs or libraries.
+ * Further information on the Mersenne Twister can be found at
+ * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ * This code was adapted to glib by Sebastian Wilhelmi.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include <math.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "main_bd.h"
+
+#if defined(PLATFORM_WINDOWS)
+#include <process.h>   // for getpid()
+#if (defined(_MSC_VER) && _MSC_VER >= 1400) || defined(__MINGW64_VERSION_MAJOR)
+extern errno_t rand_s (unsigned int *randomValue);
+#endif
+#endif
+
+
+/**
+ * GdRand:
+ *
+ * The GdRand struct is an opaque data structure. It should only be
+ * accessed through the gd_rand_* functions.
+ **/
+
+// Period parameters
+#define N 624
+#define M 397
+#define MATRIX_A   0x9908b0df // constant vector a
+#define UPPER_MASK 0x80000000 // most significant w-r bits
+#define LOWER_MASK 0x7fffffff // least significant r bits
+
+// Tempering parameters
+#define TEMPERING_MASK_B 0x9d2c5680
+#define TEMPERING_MASK_C 0xefc60000
+#define TEMPERING_SHIFT_U(y)  (y >> 11)
+#define TEMPERING_SHIFT_S(y)  (y << 7)
+#define TEMPERING_SHIFT_T(y)  (y << 15)
+#define TEMPERING_SHIFT_L(y)  (y >> 18)
+
+struct _GdRand
+{
+  unsigned int mt[N]; // the array for the state vector
+  unsigned int mti;
+};
+
+/**
+ * gd_rand_new_with_seed: (constructor)
+ * @seed: a value to initialize the random number generator
+ *
+ * Creates a new random number generator initialized with @seed.
+ *
+ * Returns: (transfer full): the new #GdRand
+ **/
+GdRand *
+gd_rand_new_with_seed (unsigned int seed)
+{
+  GdRand *rand = checked_calloc(sizeof(GdRand));
+  gd_rand_set_seed (rand, seed);
+  return rand;
+}
+
+/**
+ * gd_rand_new_with_seed_array: (constructor)
+ * @seed: an array of seeds to initialize the random number generator
+ * @seed_length: an array of seeds to initialize the random number
+ *     generator
+ *
+ * Creates a new random number generator initialized with @seed.
+ *
+ * Returns: (transfer full): the new #GdRand
+ *
+ * Since: 2.4
+ */
+GdRand *
+gd_rand_new_with_seed_array (const unsigned int *seed, unsigned int seed_length)
+{
+  GdRand *rand = checked_calloc(sizeof(GdRand));
+  gd_rand_set_seed_array (rand, seed, seed_length);
+
+  return rand;
+}
+
+/**
+ * gd_rand_new: (constructor)
+ *
+ * Creates a new random number generator initialized with a seed taken
+ * either from `/dev/urandom` (if existing) or from the current time
+ * (as a fallback).
+ *
+ * On Windows, the seed is taken from rand_s().
+ *
+ * Returns: (transfer full): the new #GdRand
+ */
+GdRand *
+gd_rand_new (void)
+{
+  unsigned int seed[4];
+
+#if defined(PLATFORM_UNIX)
+  static boolean dev_urandom_exists = TRUE;
+
+  if (dev_urandom_exists)
+  {
+    FILE *dev_urandom;
+
+    do
+    {
+      dev_urandom = fopen ("/dev/urandom", "rbe");
+    }
+    while (dev_urandom == NULL && errno == EINTR);
+
+    if (dev_urandom)
+    {
+      int r;
+
+      setvbuf (dev_urandom, NULL, _IONBF, 0);
+
+      do
+      {
+        errno = 0;
+        r = fread (seed, sizeof (seed), 1, dev_urandom);
+      }
+      while (errno == EINTR);
+
+      if (r != 1)
+        dev_urandom_exists = FALSE;
+
+      fclose (dev_urandom);
+    }
+    else
+    {
+      dev_urandom_exists = FALSE;
+    }
+  }
+
+  if (!dev_urandom_exists)
+  {
+    struct timespec now;
+
+    clock_gettime(CLOCK_REALTIME, &now);
+
+    seed[0] = now.tv_sec;
+    seed[1] = now.tv_nsec;
+    seed[2] = getpid ();
+    seed[3] = getppid ();
+  }
+#else // PLATFORM_WINDOWS
+  /* rand_s() is only available since Visual Studio 2005 and
+   * MinGW-w64 has a wrapper that will emulate rand_s() if it's not in msvcrt
+   */
+#if (defined(_MSC_VER) && _MSC_VER >= 1400) || defined(__MINGW64_VERSION_MAJOR)
+  size_t i;
+
+  for (i = 0; i < ARRAY_SIZE(seed); i++)
+    rand_s (&seed[i]);
+#else
+#warning Using insecure seed for random number generation because of missing rand_s() in Windows XP
+  GTimeVal now;
+
+  gd_get_current_time (&now);
+
+  seed[0] = now.tv_sec;
+  seed[1] = now.tv_usec;
+  seed[2] = getpid ();
+  seed[3] = 0;
+#endif
+
+#endif
+
+  return gd_rand_new_with_seed_array (seed, 4);
+}
+
+/**
+ * gd_rand_free:
+ * @rand_: a #GdRand
+ *
+ * Frees the memory allocated for the #GdRand.
+ */
+void
+gd_rand_free (GdRand *rand)
+{
+  if (rand != NULL)
+    checked_free(rand);
+}
+
+/**
+ * gd_rand_copy:
+ * @rand_: a #GdRand
+ *
+ * Copies a #GdRand into a new one with the same exact state as before.
+ * This way you can take a snapshot of the random number generator for
+ * replaying later.
+ *
+ * Returns: (transfer full): the new #GdRand
+ *
+ * Since: 2.4
+ */
+GdRand *
+gd_rand_copy (GdRand *rand)
+{
+  GdRand *new_rand;
+
+  if (rand == NULL)
+    return NULL;
+
+  new_rand = checked_calloc(sizeof(GdRand));
+  memcpy(new_rand, rand, sizeof(GdRand));
+
+  return new_rand;
+}
+
+/**
+ * gd_rand_set_seed:
+ * @rand_: a #GdRand
+ * @seed: a value to reinitialize the random number generator
+ *
+ * Sets the seed for the random number generator #GdRand to @seed.
+ */
+void
+gd_rand_set_seed (GdRand *rand, unsigned int seed)
+{
+  if (rand == NULL)
+    return;
+
+  // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
+  // In the previous version (see above), MSBs of the
+  // seed affect only MSBs of the array mt[].
+
+  rand->mt[0] = seed;
+  for (rand->mti = 1; rand->mti < N; rand->mti++)
+    rand->mt[rand->mti] = 1812433253UL *
+      (rand->mt[rand->mti - 1] ^ (rand->mt[rand->mti - 1] >> 30)) + rand->mti;
+}
+
+/**
+ * gd_rand_set_seed_array:
+ * @rand_: a #GdRand
+ * @seed: array to initialize with
+ * @seed_length: length of array
+ *
+ * Initializes the random number generator by an array of longs.
+ * Array can be of arbitrary size, though only the first 624 values
+ * are taken.  This function is useful if you have many low entropy
+ * seeds, or if you require more then 32 bits of actual entropy for
+ * your application.
+ *
+ * Since: 2.4
+ */
+void
+gd_rand_set_seed_array (GdRand *rand, const unsigned int *seed, unsigned int seed_length)
+{
+  unsigned int i, j, k;
+
+  if (rand == NULL || seed_length < 1)
+    return;
+
+  gd_rand_set_seed (rand, 19650218UL);
+
+  i = 1;
+  j = 0;
+  k = (N > seed_length ? N : seed_length);
+
+  for (; k; k--)
+  {
+    rand->mt[i] = ((rand->mt[i] ^ ((rand->mt[i - 1] ^ (rand->mt[i - 1] >> 30)) * 1664525UL))
+                  + seed[j] + j);      // non linear
+    rand->mt[i] &= 0xffffffffUL;       // for WORDSIZE > 32 machines
+    i++;
+    j++;
+
+    if (i >= N)
+    {
+      rand->mt[0] = rand->mt[N - 1];
+      i = 1;
+    }
+
+    if (j >= seed_length)
+      j = 0;
+  }
+
+  for (k = N - 1; k; k--)
+  {
+    rand->mt[i] = ((rand->mt[i] ^ ((rand->mt[i - 1] ^ (rand->mt[i - 1] >> 30)) * 1566083941UL))
+                  - i);                // non linear
+    rand->mt[i] &= 0xffffffffUL;       // for WORDSIZE > 32 machines
+    i++;
+
+    if (i >= N)
+    {
+      rand->mt[0] = rand->mt[N - 1];
+      i = 1;
+    }
+  }
+
+  rand->mt[0] = 0x80000000UL;          // MSB is 1; assuring non-zero initial array
+}
+
+/**
+ * gd_rand_boolean:
+ * @rand_: a #GdRand
+ *
+ * Returns a random #boolean from @rand_.
+ * This corresponds to an unbiased coin toss.
+ *
+ * Returns: a random #boolean
+ */
+/**
+ * gd_rand_int:
+ * @rand_: a #GdRand
+ *
+ * Returns the next random unsigned int from @rand_ equally distributed over
+ * the range [0..2^32-1].
+ *
+ * Returns: a random number
+ */
+unsigned int
+gd_rand_int (GdRand *rand)
+{
+  unsigned int y;
+  static const unsigned int mag01[2] = { 0x0, MATRIX_A };
+  // mag01[x] = x * MATRIX_A  for x=0,1
+
+  if (rand == NULL)
+    return 0;
+
+  if (rand->mti >= N)
+  {
+    // generate N words at one time
+    int kk;
+
+    for (kk = 0; kk < N - M; kk++)
+    {
+      y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk + 1] & LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+
+    for (; kk < N - 1; kk++)
+    {
+      y = (rand->mt[kk] & UPPER_MASK) | (rand->mt[kk + 1] & LOWER_MASK);
+      rand->mt[kk] = rand->mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
+    }
+
+    y = (rand->mt[N - 1] & UPPER_MASK) | (rand->mt[0] & LOWER_MASK);
+    rand->mt[N - 1] = rand->mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];
+
+    rand->mti = 0;
+  }
+
+  y = rand->mt[rand->mti++];
+  y ^= TEMPERING_SHIFT_U(y);
+  y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
+  y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
+  y ^= TEMPERING_SHIFT_L(y);
+
+  return y;
+}
+
+// transform [0..2^32] -> [0..1]
+#define GD_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
+
+/**
+ * gd_rand_int_range:
+ * @rand_: a #GdRand
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns the next random #int from @rand_ equally distributed over
+ * the range [@begin..@end-1].
+ *
+ * Returns: a random number
+ */
+int
+gd_rand_int_range (GdRand *rand, int begin, int end)
+{
+  unsigned int dist = end - begin;
+  unsigned int random = 0;
+
+  if (rand == NULL || end <= begin)
+    return begin;
+
+  if (dist == 0)
+    return begin;
+
+  /* maxvalue is set to the predecessor of the greatest
+   * multiple of dist less or equal 2^32.
+   */
+  unsigned int maxvalue;
+  if (dist <= 0x80000000u) // 2^31
+  {
+    // maxvalue = 2^32 - 1 - (2^32 % dist)
+    unsigned int leftover = (0x80000000u % dist) * 2;
+    if (leftover >= dist) leftover -= dist;
+    maxvalue = 0xffffffffu - leftover;
+  }
+  else
+  {
+    maxvalue = dist - 1;
+  }
+
+  do
+    random = gd_rand_int (rand);
+  while (random > maxvalue);
+
+  random %= dist;
+
+  return begin + random;
+}
+
+/**
+ * gd_rand_double:
+ * @rand_: a #GRand
+ *
+ * Returns the next random #double from @rand_ equally distributed over
+ * the range [0..1).
+ *
+ * Returns: a random number
+ */
+double
+gd_rand_double (GdRand *rand)
+{
+  /* We set all 52 bits after the point for this, not only the first
+     32. That's why we need two calls to gd_rand_int */
+  double retval = gd_rand_int(rand) * GD_RAND_DOUBLE_TRANSFORM;
+  retval = (retval + gd_rand_int(rand)) * GD_RAND_DOUBLE_TRANSFORM;
+
+  /* The following might happen due to very bad rounding luck, but
+   * actually this should be more than rare, we just try again then */
+  if (retval >= 1.0)
+    return gd_rand_double (rand);
+
+  return retval;
+}
+
+/**
+ * gd_rand_double_range:
+ * @rand_: a #GRand
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns the next random #double from @rand_ equally distributed over
+ * the range [@begin..@end).
+ *
+ * Returns: a random number
+ */
+double
+gd_rand_double_range (GdRand *rand, double begin, double end)
+{
+  double r;
+
+  r = gd_rand_double(rand);
+
+  return r * end - (r - 1) * begin;
+}
+
+static GdRand *
+get_global_random (void)
+{
+  static GdRand *global_random;
+
+  // called while locked
+  if (!global_random)
+    global_random = gd_rand_new();
+
+  return global_random;
+}
+
+/**
+ * gd_random_boolean:
+ *
+ * Returns a random #gboolean.
+ * This corresponds to an unbiased coin toss.
+ *
+ * Returns: a random #gboolean
+ */
+/**
+ * gd_random_int:
+ *
+ * Return a random #guint32 equally distributed over the range
+ * [0..2^32-1].
+ *
+ * Returns: a random number
+ */
+unsigned int
+gd_random_int (void)
+{
+  unsigned int result;
+
+  result = gd_rand_int(get_global_random());
+
+  return result;
+}
+
+/**
+ * gd_random_int_range:
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns a random #int equally distributed over the range
+ * [@begin..@end-1].
+ *
+ * Returns: a random number
+ */
+int
+gd_random_int_range (int begin, int end)
+{
+  int result;
+
+  result = gd_rand_int_range (get_global_random(), begin, end);
+
+  return result;
+}
+
+/**
+ * gd_random_double:
+ *
+ * Returns a random #double equally distributed over the range [0..1).
+ *
+ * Returns: a random number
+ */
+double
+gd_random_double (void)
+{
+  double result;
+
+  result = gd_rand_double(get_global_random());
+
+  return result;
+}
+
+/**
+ * gd_random_double_range:
+ * @begin: lower closed bound of the interval
+ * @end: upper open bound of the interval
+ *
+ * Returns a random #double equally distributed over the range
+ * [@begin..@end).
+ *
+ * Returns: a random number
+ */
+double
+gd_random_double_range (double begin, double end)
+{
+  double result;
+
+  result = gd_rand_double_range(get_global_random(), begin, end);
+
+  return result;
+}
diff --git a/src/game_bd/bd_random.h b/src/game_bd/bd_random.h
new file mode 100644 (file)
index 0000000..ec6c503
--- /dev/null
@@ -0,0 +1,71 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Originally developed and coded by Makoto Matsumoto and Takuji
+ * Nishimura.  Please mail <matumoto@math.keio.ac.jp>, if you're using
+ * code from this file in your own programs or libraries.
+ * Further information on the Mersenne Twister can be found at
+ * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ * This code was adapted to glib by Sebastian Wilhelmi.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef BD_RANDOM_H
+#define BD_RANDOM_H
+
+
+typedef struct _GdRand GdRand;
+
+/* GdRand - a good and fast random number generator: Mersenne Twister
+ * see http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html for more info.
+ * The range functions return a value in the interval [begin, end).
+ * int          -> [0..2^32-1]
+ * int_range    -> [begin..end-1]
+ * double       -> [0..1)
+ * double_range -> [begin..end)
+ */
+
+GdRand      *gd_rand_new_with_seed(unsigned int seed);
+GdRand      *gd_rand_new_with_seed_array(const unsigned int *seed, unsigned int seed_length);
+GdRand      *gd_rand_new(void);
+void         gd_rand_free(GdRand *rand);
+GdRand      *gd_rand_copy(GdRand *rand);
+void         gd_rand_set_seed(GdRand *rand, unsigned int seed);
+void         gd_rand_set_seed_array(GdRand *rand_, const unsigned int *seed, unsigned int seed_length);
+#define      gd_rand_boolean(rand_) ((gd_rand_int (rand_) & (1 << 15)) != 0)
+unsigned int gd_rand_int(GdRand *rand_);
+int          gd_rand_int_range(GdRand *rand_, int begin, int end);
+double       gd_rand_double(GdRand *rand_);
+double       gd_rand_double_range(GdRand *rand_, double begin, double end);
+
+void         gd_random_set_seed(unsigned int seed);
+#define      gd_random_boolean() ((gd_random_int () & (1 << 15)) != 0)
+unsigned int gd_random_int(void);
+int          gd_random_int_range(int begin, int end);
+
+double       gd_random_double(void);
+double       gd_random_double_range(double  begin, double  end);
+
+#endif // BD_RANDOM_H
diff --git a/src/game_bd/bd_sound.c b/src/game_bd/bd_sound.c
new file mode 100644 (file)
index 0000000..e1bdfc4
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "main_bd.h"
+
+
+/*
+  The C64 sound chip (the SID) had 3 channels. Boulder Dash used all 3 of them.
+
+  Different channels were used for different sounds.
+
+  Channel 1: other small sounds, ie. diamonds falling, boulders rolling.
+
+  Channel 2: Walking, diamond collecting and explosion; also time running out
+             sound.
+
+  Channel 3: amoeba sound, magic wall sound, cave cover & uncover sound, and
+             the crack sound (gate open)
+
+  Sounds have precedence over each other. Ie. the crack sound is given
+  precedence over other sounds (amoeba, for example.)
+  Different channels also behave differently. Channel 2 sounds are not stopped,
+  ie. walking can not be heard, until the explosion sound is finished playing
+  completely.
+
+  Explosions are always restarted, though. This is controlled by the array
+  defined in cave.c.
+
+  Channel 1 sounds are always stopped, if a new sound is requested.
+
+  Here we implement this a bit differently. We use samples, instead of
+  synthesizing the sounds. By stopping samples, sometimes small clicks
+  generate. Therefore we do not stop them, rather fade them out quickly.
+  (The SID had filters, which stopped these small clicks.)
+
+  Also, channel 1 and 2 should be stopped very often. So I decided to use two
+  SDL_Mixer channels to emulate one C64 channel; and they are used alternating.
+  SDL channel 4 is the "backup" channel 1, channel 5 is the backup channel 2.
+  Other channels have the same indexes.
+*/
+
+
+#define MAX_CHANNELS           5
+
+typedef enum _sound_flag
+{
+  GD_SP_LOOPED  = 1 << 0,
+  GD_SP_FORCE   = 1 << 1,  // force restart, regardless of precedence level
+} GdSoundFlag;
+
+typedef struct _sound_property
+{
+  GdSound sound;
+  int channel;        // channel this sound is played on.
+  int precedence;     // greater numbers will have precedence.
+  int flags;
+} SoundProperty;
+
+static SoundProperty sound_flags[] =
+{
+  { 0, GD_S_NONE,                      0, 0                                    },
+
+  // channel 1 sounds.
+  // CHANNEL 1 SOUNDS ARE ALWAYS RESTARTED, so no need for GD_SP_FORCE flag.
+  { GD_S_STONE_PUSHING,                        1, 10                                   },
+  { GD_S_STONE_FALLING,                        1, 10                                   },
+  { GD_S_STONE_IMPACT,                 1, 10                                   },
+  { GD_S_MEGA_STONE_PUSHING,           1, 10                                   },
+  { GD_S_MEGA_STONE_FALLING,           1, 10                                   },
+  { GD_S_MEGA_STONE_IMPACT,            1, 10                                   },
+  { GD_S_FLYING_STONE_PUSHING,         1, 10                                   },
+  { GD_S_FLYING_STONE_FALLING,         1, 10                                   },
+  { GD_S_FLYING_STONE_IMPACT,          1, 10                                   },
+  { GD_S_WAITING_STONE_PUSHING,                1, 10                                   },
+  { GD_S_CHASING_STONE_PUSHING,                1, 10                                   },
+  // nut falling is relatively silent, so low precedence.
+  { GD_S_NUT_PUSHING,                  1, 8                                    },
+  { GD_S_NUT_FALLING,                  1, 8                                    },
+  { GD_S_NUT_IMPACT,                   1, 8                                    },
+  // higher precedence than a stone bouncing.
+  { GD_S_NUT_CRACKING,                 1, 12                                   },
+  // sligthly lower precedence, as stones and diamonds should be "louder"
+  { GD_S_DIRT_BALL_FALLING,            1, 8                                    },
+  { GD_S_DIRT_BALL_IMPACT,             1, 8                                    },
+  { GD_S_DIRT_LOOSE_FALLING,           1, 8                                    },
+  { GD_S_DIRT_LOOSE_IMPACT,            1, 8                                    },
+  { GD_S_NITRO_PACK_PUSHING,           1, 10                                   },
+  { GD_S_NITRO_PACK_FALLING,           1, 10                                   },
+  { GD_S_NITRO_PACK_IMPACT,            1, 10                                   },
+  { GD_S_FALLING_WALL_FALLING,         1, 10                                   },
+  { GD_S_FALLING_WALL_IMPACT,          1, 10                                   },
+  { GD_S_EXPANDING_WALL,               1, 10                                   },
+  { GD_S_WALL_REAPPEARING,             1, 9                                    },
+  { GD_S_DIAMOND_FALLING_RANDOM,       1, 10                                   },
+  { GD_S_DIAMOND_FALLING_1,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_2,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_3,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_4,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_5,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_6,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_7,            1, 10                                   },
+  { GD_S_DIAMOND_FALLING_8,            1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_RANDOM,                1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_1,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_2,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_3,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_4,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_5,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_6,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_7,             1, 10                                   },
+  { GD_S_DIAMOND_IMPACT_8,             1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_RANDOM,        1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_1,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_2,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_3,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_4,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_5,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_6,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_7,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_FALLING_8,     1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_RANDOM, 1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_1,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_2,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_3,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_4,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_5,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_6,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_7,      1, 10                                   },
+  { GD_S_FLYING_DIAMOND_IMPACT_8,      1, 10                                   },
+  // diamond collect sound has precedence over everything.
+  { GD_S_DIAMOND_COLLECTING,           1, 100                                  },
+  { GD_S_FLYING_DIAMOND_COLLECTING,    1, 100                                  },
+
+  // collect sounds have higher precedence than falling sounds and the like.
+  { GD_S_SKELETON_COLLECTING,          1, 100                                  },
+  { GD_S_PNEUMATIC_COLLECTING,         1, 50                                   },
+  { GD_S_BOMB_COLLECTING,              1, 50                                   },
+  { GD_S_CLOCK_COLLECTING,             1, 50                                   },
+  { GD_S_SWEET_COLLECTING,             1, 50                                   },
+  { GD_S_KEY_COLLECTING,               1, 50                                   },
+  { GD_S_DIAMOND_KEY_COLLECTING,       1, 50                                   },
+  // slime has lower precedence than diamond and stone falling sounds.
+  { GD_S_SLIME,                                1, 5                                    },
+  // lava has low precedence, too.
+  { GD_S_LAVA,                         1, 5                                    },
+  { GD_S_REPLICATOR,                   1, 5                                    },
+  // same for acid, even lower.
+  { GD_S_ACID_SPREADING,               1, 3                                    },
+  // same for bladder.
+  { GD_S_BLADDER_MOVING,               1, 5                                    },
+  { GD_S_BLADDER_PUSHING,              1, 5                                    },
+  { GD_S_BLADDER_CONVERTING,           1, 8                                    },
+  { GD_S_BLADDER_SPENDER,              1, 8                                    },
+  // very low precedence. biters tend to produce too much sound.
+  { GD_S_BITER_EATING,                 1, 3                                    },
+
+  // channel2 sounds.
+  { GD_S_DOOR_OPENING,                 2, 10                                   },
+  { GD_S_DIRT_WALKING,                 2, 10                                   },
+  { GD_S_EMPTY_WALKING,                        2, 10                                   },
+  { GD_S_STIRRING,                     2, 10                                   },
+  { GD_S_BOX_PUSHING,                  2, 10                                   },
+  { GD_S_TELEPORTER,                   2, 10                                   },
+  // timeout sounds have increasing precedence so they are always started
+  { GD_S_TIMEOUT_10,                   2, 20                                   },
+  // timeout sounds are examples which do not need "force restart" flag.
+  { GD_S_TIMEOUT_9,                    2, 21                                   },
+  { GD_S_TIMEOUT_8,                    2, 22                                   },
+  { GD_S_TIMEOUT_7,                    2, 23                                   },
+  { GD_S_TIMEOUT_6,                    2, 24                                   },
+  { GD_S_TIMEOUT_5,                    2, 25                                   },
+  { GD_S_TIMEOUT_4,                    2, 26                                   },
+  { GD_S_TIMEOUT_3,                    2, 27                                   },
+  { GD_S_TIMEOUT_2,                    2, 28                                   },
+  { GD_S_TIMEOUT_1,                    2, 29                                   },
+  { GD_S_TIMEOUT_0,                    2, 150, GD_SP_FORCE                     },
+  { GD_S_EXPLODING,                    2, 100, GD_SP_FORCE                     },
+  { GD_S_BOMB_EXPLODING,               2, 100, GD_SP_FORCE                     },
+  { GD_S_GHOST_EXPLODING,              2, 100, GD_SP_FORCE                     },
+  { GD_S_VOODOO_EXPLODING,             2, 100, GD_SP_FORCE                     },
+  { GD_S_NITRO_PACK_EXPLODING,         2, 100, GD_SP_FORCE                     },
+  { GD_S_BOMB_PLACING,                 2, 10                                   },
+  // precedence larger than normal, but smaller than timeout sounds
+  { GD_S_FINISHED,                     2, 15,  GD_SP_FORCE | GD_SP_LOOPED      },
+  { GD_S_SWITCH_BITER,                 2, 10                                   },
+  { GD_S_SWITCH_CREATURES,             2, 10                                   },
+  { GD_S_SWITCH_GRAVITY,               2, 10                                   },
+  { GD_S_SWITCH_EXPANDING,             2, 10                                   },
+  { GD_S_SWITCH_CONVEYOR,              2, 10                                   },
+  { GD_S_SWITCH_REPLICATOR,            2, 10                                   },
+
+  // channel 3 sounds.
+  { GD_S_AMOEBA,                       3, 30,  GD_SP_LOOPED                    },
+  { GD_S_AMOEBA_MAGIC,                 3, 40,  GD_SP_LOOPED                    },
+  { GD_S_MAGIC_WALL,                   3, 35,  GD_SP_LOOPED                    },
+  { GD_S_COVERING,                     3, 100, GD_SP_LOOPED                    },
+  { GD_S_PNEUMATIC_HAMMER,             3, 50,  GD_SP_LOOPED                    },
+  { GD_S_WATER,                                3, 20,  GD_SP_LOOPED                    },
+  { GD_S_CRACKING,                     3, 150                                  },
+  { GD_S_GRAVITY_CHANGING,             3, 60                                   },
+
+  // other sounds
+  // the bonus life sound has nothing to do with the cave.
+  // playing on channel 4.
+  { GD_S_BONUS_LIFE,                   4, 0                                    },
+};
+
+struct GdSoundInfo
+{
+  int x, y;
+  int element;
+  int sound;
+};
+
+static GdSound snd_playing[MAX_CHANNELS];
+struct GdSoundInfo sound_info_to_play[MAX_CHANNELS];
+struct GdSoundInfo sound_info_playing[MAX_CHANNELS];
+
+static boolean gd_sound_is_looped(GdSound sound)
+{
+  return (sound_flags[sound].flags & GD_SP_LOOPED) != 0;
+}
+
+static boolean gd_sound_force_start(GdSound sound)
+{
+  return (sound_flags[sound].flags & GD_SP_FORCE) != 0;
+}
+
+static int gd_sound_get_channel(GdSound sound)
+{
+  return sound_flags[sound].channel;
+}
+
+static int gd_sound_get_precedence(GdSound sound)
+{
+  return sound_flags[sound].precedence;
+}
+
+static GdSound sound_playing(int channel)
+{
+  struct GdSoundInfo *si = &sound_info_playing[channel];
+
+  // check if sound has finished playing
+  if (snd_playing[channel] != GD_S_NONE)
+    if (!isSoundPlaying_BD(si->element, si->sound))
+      snd_playing[channel] = GD_S_NONE;
+
+  return snd_playing[channel];
+}
+
+static void halt_channel(int channel)
+{
+  struct GdSoundInfo *si = &sound_info_playing[channel];
+
+#if 0
+  if (isSoundPlaying_BD(si->element, si->sound))
+    printf("::: stop sound %d\n", si->sound);
+#endif
+
+  if (isSoundPlaying_BD(si->element, si->sound))
+    StopSound_BD(si->element, si->sound);
+
+  snd_playing[channel] = GD_S_NONE;
+}
+
+static void play_channel_at_position(int channel)
+{
+  struct GdSoundInfo *si = &sound_info_to_play[channel];
+
+  PlayLevelSound_BD(si->x, si->y, si->element, si->sound);
+
+  sound_info_playing[channel] = *si;
+}
+
+static void play_sound(int channel, GdSound sound)
+{
+  // channel 1 and channel 4 are used alternating
+  // channel 2 and channel 5 are used alternating
+  static const GdSound diamond_falling_sounds[] =
+  {
+    GD_S_DIAMOND_FALLING_1,
+    GD_S_DIAMOND_FALLING_2,
+    GD_S_DIAMOND_FALLING_3,
+    GD_S_DIAMOND_FALLING_4,
+    GD_S_DIAMOND_FALLING_5,
+    GD_S_DIAMOND_FALLING_6,
+    GD_S_DIAMOND_FALLING_7,
+    GD_S_DIAMOND_FALLING_8,
+  };
+  static const GdSound diamond_impact_sounds[] =
+  {
+    GD_S_DIAMOND_IMPACT_1,
+    GD_S_DIAMOND_IMPACT_2,
+    GD_S_DIAMOND_IMPACT_3,
+    GD_S_DIAMOND_IMPACT_4,
+    GD_S_DIAMOND_IMPACT_5,
+    GD_S_DIAMOND_IMPACT_6,
+    GD_S_DIAMOND_IMPACT_7,
+    GD_S_DIAMOND_IMPACT_8,
+  };
+  static const GdSound flying_diamond_falling_sounds[] =
+  {
+    GD_S_FLYING_DIAMOND_FALLING_1,
+    GD_S_FLYING_DIAMOND_FALLING_2,
+    GD_S_FLYING_DIAMOND_FALLING_3,
+    GD_S_FLYING_DIAMOND_FALLING_4,
+    GD_S_FLYING_DIAMOND_FALLING_5,
+    GD_S_FLYING_DIAMOND_FALLING_6,
+    GD_S_FLYING_DIAMOND_FALLING_7,
+    GD_S_FLYING_DIAMOND_FALLING_8,
+  };
+  static const GdSound flying_diamond_impact_sounds[] =
+  {
+    GD_S_FLYING_DIAMOND_IMPACT_1,
+    GD_S_FLYING_DIAMOND_IMPACT_2,
+    GD_S_FLYING_DIAMOND_IMPACT_3,
+    GD_S_FLYING_DIAMOND_IMPACT_4,
+    GD_S_FLYING_DIAMOND_IMPACT_5,
+    GD_S_FLYING_DIAMOND_IMPACT_6,
+    GD_S_FLYING_DIAMOND_IMPACT_7,
+    GD_S_FLYING_DIAMOND_IMPACT_8,
+  };
+
+  if (sound == GD_S_NONE)
+    return;
+
+  // change diamond falling random to a selected diamond falling sound.
+  if (sound == GD_S_DIAMOND_FALLING_RANDOM)
+    sound = diamond_falling_sounds[gd_random_int_range(0, 8)];
+  else if (sound == GD_S_DIAMOND_IMPACT_RANDOM)
+    sound = diamond_impact_sounds[gd_random_int_range(0, 8)];
+  else if (sound == GD_S_FLYING_DIAMOND_FALLING_RANDOM)
+    sound = flying_diamond_falling_sounds[gd_random_int_range(0, 8)];
+  else if (sound == GD_S_FLYING_DIAMOND_IMPACT_RANDOM)
+    sound = flying_diamond_impact_sounds[gd_random_int_range(0, 8)];
+
+  // channel 1 may have been changed to channel 4 above.
+
+  if (!gd_sound_is_looped(sound))
+    halt_channel(channel);
+
+  play_channel_at_position(channel);
+
+  snd_playing[channel] = sound;
+}
+
+void gd_sound_init(void)
+{
+  int i;
+
+  for (i = 0; i < GD_S_MAX; i++)
+    if (sound_flags[i].sound != i)
+      Fail("sound db index mismatch: %d", i);
+
+  for (i = 0; i < MAX_CHANNELS; i++)
+    snd_playing[i] = GD_S_NONE;
+}
+
+void gd_sound_off(void)
+{
+  int i;
+
+  // stop all sounds.
+  for (i = 0; i < ARRAY_SIZE(snd_playing); i++)
+    halt_channel(i);
+}
+
+void gd_sound_play_bonus_life(void)
+{
+  // required to set extended sound information for native sound engine
+  gd_sound_play(NULL, GD_S_BONUS_LIFE, O_NONE, -1, -1);
+
+  // now play the sound directly (on non-standard sound channel)
+  play_sound(gd_sound_get_channel(GD_S_BONUS_LIFE), GD_S_BONUS_LIFE);
+}
+
+static void play_sounds(GdSound sound1, GdSound sound2, GdSound sound3)
+{
+  // CHANNEL 1 is for small sounds
+  if (sound1 != GD_S_NONE)
+  {
+    // start new sound if higher or same precedence than the one currently playing
+    if (gd_sound_get_precedence(sound1) >= gd_sound_get_precedence(sound_playing(1)))
+      play_sound(1, sound1);
+  }
+  else
+  {
+    // only interrupt looped sounds. non-looped sounds will go away automatically.
+    if (gd_sound_is_looped(sound_playing(1)))
+      halt_channel(1);
+  }
+
+  // CHANNEL 2 is for walking, explosions
+  // if no sound requested, do nothing.
+  if (sound2 != GD_S_NONE)
+  {
+    boolean play = FALSE;
+
+    // always start if not currently playing a sound.
+    if (sound_playing(2) == GD_S_NONE ||
+       gd_sound_force_start(sound2) ||
+       gd_sound_get_precedence(sound2) > gd_sound_get_precedence(sound_playing(2)))
+      play = TRUE;
+
+    // if figured out to play: do it.
+    // (if the requested sound is looped, this is required to continue playing it)
+    if (play)
+      play_sound(2, sound2);
+  }
+  else
+  {
+    // only interrupt looped sounds. non-looped sounds will go away automatically.
+    if (gd_sound_is_looped(sound_playing(2)))
+      halt_channel(2);
+  }
+
+  // CHANNEL 3 is for crack sound, amoeba and magic wall.
+  if (sound3 != GD_S_NONE)
+  {
+    boolean play = TRUE;
+
+    // if requests a non-looped sound, play that immediately.
+    // that can be a crack sound, gravity change, new life, ...
+
+    // do not interrupt the previous sound, if it is non-looped.
+    // later calls of this function will probably contain the same sound3,
+    // and then it will be set.
+    if (!gd_sound_is_looped(sound_playing(3)) &&
+       gd_sound_is_looped(sound3) &&
+       sound_playing(3) != GD_S_NONE)
+      play = FALSE;
+
+    // if figured out to play: do it.
+    if (play)
+      play_sound(3, sound3);
+  }
+  else
+  {
+    // sound3 = none, so interrupt sound requested.
+    // only interrupt looped sounds. non-looped sounds will go away automatically.
+    if (gd_sound_is_looped(sound_playing(3)))
+      halt_channel(3);
+  }
+}
+
+void gd_sound_play_cave(GdCave *cave)
+{
+  play_sounds(cave->sound1, cave->sound2, cave->sound3);
+}
+
+static void gd_sound_info_to_play(int channel, int x, int y, int element, int sound)
+{
+  struct GdSoundInfo *si = &sound_info_to_play[channel];
+
+  si->x = x;
+  si->y = y;
+  si->element = element;
+  si->sound = sound;
+}
+
+// plays sound in a cave
+void gd_sound_play(GdCave *cave, GdSound sound, GdElement element, int x, int y)
+{
+  if (sound == GD_S_NONE)
+    return;
+
+  // do not play sounds when fast-forwarding until player hatched
+  if (setup.bd_skip_hatching && !game_bd.game->cave->hatched &&
+      game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
+    return;
+
+  // when using native sound engine or if no position specified, use middle screen position
+  if (game.use_native_bd_sound_engine || (x == -1 && y == -1))
+  {
+    x = get_play_area_w() / 2 + get_scroll_x();
+    y = get_play_area_h() / 2 + get_scroll_y();
+  }
+
+  if (!game.use_native_bd_sound_engine)
+  {
+    // when not using native sound engine, just play the sound
+    PlayLevelSound_BD(x, y, element, sound);
+
+    return;
+  }
+
+  GdSound *s = &sound;         // use reliable default value
+  int channel = gd_sound_get_channel(sound);
+
+  switch (channel)
+  {
+    case 1: s = &cave->sound1; break;
+    case 2: s = &cave->sound2; break;
+    case 3: s = &cave->sound3; break;
+    default: break;
+  }
+
+  if (gd_sound_get_precedence(sound) >= gd_sound_get_precedence(*s))
+  {
+    // set sound
+    *s = sound;
+
+    // set extended sound information for native sound engine
+    gd_sound_info_to_play(channel, x, y, element, sound);
+  }
+}
diff --git a/src/game_bd/bd_sound.h b/src/game_bd/bd_sound.h
new file mode 100644 (file)
index 0000000..ccce604
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BD_SOUND_H
+#define BD_SOUND_H
+
+#include "bd_cave.h"
+
+
+// init sound. allows setting buffer size (for replays saving), 0 for default
+void gd_sound_init(void);
+void gd_sound_off(void);
+void gd_sound_play_cave(GdCave *cave);
+void gd_sound_play_bonus_life(void);
+void gd_sound_play(GdCave *cave, GdSound sound, GdElement element, int x, int y);
+
+#endif // BD_SOUND_H
diff --git a/src/game_bd/export_bd.h b/src/game_bd/export_bd.h
new file mode 100644 (file)
index 0000000..a060e2e
--- /dev/null
@@ -0,0 +1,128 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// export_bd.h
+// ============================================================================
+
+#ifndef EXPORT_BD_H
+#define EXPORT_BD_H
+
+// ============================================================================
+// functions and definitions exported from game_bd to main program
+// ============================================================================
+
+#include "bd_cave.h"
+#include "bd_elements.h"
+#include "bd_gameplay.h"
+
+
+// ----------------------------------------------------------------------------
+// constant definitions
+// ----------------------------------------------------------------------------
+
+#define BD_MAX_CAVE_WIDTH              MAX_PLAYFIELD_WIDTH
+#define BD_MAX_CAVE_HEIGHT             MAX_PLAYFIELD_HEIGHT
+
+
+// ----------------------------------------------------------------------------
+// data structure definitions
+// ----------------------------------------------------------------------------
+
+struct GameInfo_BD
+{
+  GdGame *game;
+
+  unsigned int random_seed;
+
+  boolean level_solved;
+  boolean game_over;
+  boolean cover_screen;
+
+  // needed for updating panel
+  int time_played;
+  int gems_still_needed;
+  int score;
+};
+
+struct LevelInfo_BD
+{
+  GdCave *cave;
+  GdReplay *replay;
+
+  int cave_nr;
+  int level_nr;
+
+  boolean loaded_from_caveset;
+};
+
+struct GraphicInfo_BD
+{
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int width, height;
+
+  int graphic;
+  int frame;
+};
+
+struct EngineSnapshotInfo_BD
+{
+};
+
+
+// ----------------------------------------------------------------------------
+// exported functions
+// ----------------------------------------------------------------------------
+
+extern struct GameInfo_BD game_bd;
+extern struct LevelInfo_BD native_bd_level;
+extern struct GraphicInfo_BD graphic_info_bd_object[O_MAX_ALL][8];
+extern struct GraphicInfo_BD graphic_info_bd_color_template;
+extern struct EngineSnapshotInfo_BD engine_snapshot_bd;
+
+void bd_open_all(void);
+void bd_close_all(void);
+
+int map_action_RND_to_BD(int);
+int map_action_BD_to_RND(int);
+
+boolean checkGameRunning_BD(void);
+boolean checkGamePlaying_BD(void);
+boolean checkBonusTime_BD(void);
+int getFramesPerSecond_BD(void);
+int getTimeLeft_BD(void);
+
+void InitGfxBuffers_BD(void);
+
+void setLevelInfoToDefaults_BD_Ext(int, int);
+void setLevelInfoToDefaults_BD(void);
+boolean LoadNativeLevel_BD(char *, int, boolean);
+boolean SaveNativeLevel_BD(char *);
+void DumpLevelset_BD(void);
+
+void PreparePreviewTileBitmap_BD(Bitmap *, int);
+void SetPreviewTileBitmapReference_BD(Bitmap *);
+Bitmap *GetPreviewTileBitmap_BD(Bitmap *);
+
+unsigned int InitEngineRandom_BD(int);
+void InitGameEngine_BD(void);
+void GameActions_BD(byte[MAX_PLAYERS]);
+
+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 skip_bd_falling_sounds(void);
+
+Bitmap **GetTitleScreenBitmaps_BD(void);
+void CoverScreen_BD(void);
+
+void BlitScreenToBitmap_BD(Bitmap *);
+void RedrawPlayfield_BD(boolean);
+
+#endif // EXPORT_BD_H
diff --git a/src/game_bd/game_bd.h b/src/game_bd/game_bd.h
new file mode 100644 (file)
index 0000000..a24222a
--- /dev/null
@@ -0,0 +1,20 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// game_bd.h
+// ============================================================================
+
+#ifndef GAME_BD_H
+#define GAME_BD_H
+
+#define GAME_BD_VERSION_1_0_0
+
+#include "import_bd.h"
+#include "export_bd.h"
+
+#endif // GAME_BD_H
diff --git a/src/game_bd/import_bd.h b/src/game_bd/import_bd.h
new file mode 100644 (file)
index 0000000..ace426d
--- /dev/null
@@ -0,0 +1,43 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// import_bd.h
+// ============================================================================
+
+#ifndef IMPORT_BD_H
+#define IMPORT_BD_H
+
+// ============================================================================
+// functions and definitions imported from main program to game_bd
+// ============================================================================
+
+#include "../libgame/libgame.h"
+#include "../game.h"
+
+#include "export_bd.h"
+
+
+// ----------------------------------------------------------------------------
+// imported functions
+// ----------------------------------------------------------------------------
+
+void InitGraphicInfo_BD(void);
+
+void PlayLevelSound_BD(int, int, int, int);
+void StopSound_BD(int, int);
+boolean isSoundPlaying_BD(int, int);
+
+void BackToFront(void);
+
+byte *TapePlayAction_BD(void);
+byte *TapeCorrectAction_BD(byte *);
+boolean TapeIsPlaying_ReplayBD(void);
+
+boolean isLevelEditorTestGame(void);
+
+#endif // IMPORT_BD_H
diff --git a/src/game_bd/main_bd.c b/src/game_bd/main_bd.c
new file mode 100644 (file)
index 0000000..06ecfd0
--- /dev/null
@@ -0,0 +1,533 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main_bd.c
+// ============================================================================
+
+#include "main_bd.h"
+
+
+struct GameInfo_BD game_bd;
+struct LevelInfo_BD native_bd_level;
+struct EngineSnapshotInfo_BD engine_snapshot_bd;
+
+
+// ============================================================================
+// initialization functions
+// ============================================================================
+
+void InitGfxBuffers_BD(void)
+{
+  ReCreateBitmap(&gd_screen_bitmap, SXSIZE, SYSIZE);
+
+  set_cell_size(TILESIZE_VAR);
+  set_play_area(SXSIZE, SYSIZE);
+}
+
+void bd_open_all(void)
+{
+  InitGraphicInfo_BD();
+
+  gd_cave_init();
+  gd_cave_db_init();
+
+  gd_c64_import_init_tables();
+
+  gd_caveset_clear();
+
+  gd_init_play_area();
+
+  gd_sound_init();
+}
+
+void bd_close_all(void)
+{
+}
+
+
+// ============================================================================
+// level file functions
+// ============================================================================
+
+void setLevelInfoToDefaults_BD_Ext(int width, int height)
+{
+  GdCave *cave = native_bd_level.cave;
+
+  if (cave != NULL)
+    gd_cave_free(cave);
+
+  // get empty cave, using default values
+  cave = gd_cave_new();
+
+  // set cave size, if defined
+  if (width > 0 && height > 0)
+  {
+    cave->w = width;
+    cave->h = height;
+
+    cave->x1 = 0;
+    cave->y1 = 0;
+    cave->x2 = cave->w - 1;
+    cave->y2 = cave->h - 1;
+  }
+
+  gd_flatten_cave(cave, 0);
+
+  cave->selectable = TRUE;
+  cave->intermission = FALSE;
+
+  native_bd_level.cave = cave;
+  native_bd_level.replay = NULL;
+
+  native_bd_level.cave_nr = 0;
+  native_bd_level.level_nr = 0;
+
+  native_bd_level.loaded_from_caveset = FALSE;
+}
+
+void setLevelInfoToDefaults_BD(void)
+{
+  setLevelInfoToDefaults_BD_Ext(0, 0);
+}
+
+static List *getNativeLevelReplay_BD_Ext(List *item, boolean only_successful_replays)
+{
+  // look for replay that was recorded for the current difficulty level
+  while (item != NULL &&
+        (item->data == NULL ||
+         (((GdReplay *)item->data)->success == FALSE && only_successful_replays) ||
+         ((GdReplay *)item->data)->level != native_bd_level.level_nr))
+    item = item->next;
+
+  return item;
+}
+
+static List *getNativeLevelReplay_BD(List *replays)
+{
+  // 1st try: look for successful replay
+  List *item = getNativeLevelReplay_BD_Ext(replays, TRUE);
+
+  if (item != NULL)
+    return item;
+
+  // 2nd try: look for any replay
+  return getNativeLevelReplay_BD_Ext(replays, FALSE);
+}
+
+boolean LoadNativeLevel_BD(char *filename, int level_pos, boolean level_info_only)
+{
+  static char *filename_loaded = NULL;
+
+  if (filename_loaded == NULL || !strEqual(filename, filename_loaded))
+  {
+    if (!gd_caveset_load_from_file(filename))
+    {
+      if (!level_info_only)
+       Warn("cannot load BD cave set from file '%s'", filename);
+
+      return FALSE;
+    }
+
+    setString(&filename_loaded, filename);
+  }
+
+  if (level_pos < 0 || level_pos >= 5 * gd_caveset_count())
+  {
+    Warn("invalid level position %d in BD cave set", level_pos);
+
+    return FALSE;
+  }
+
+  native_bd_level.cave_nr  = level_pos % gd_caveset_count();
+  native_bd_level.level_nr = level_pos / gd_caveset_count();
+
+  if (native_bd_level.cave != NULL)
+    gd_cave_free(native_bd_level.cave);
+
+  // get selected cave, prepared for playing
+  native_bd_level.cave = gd_get_prepared_cave_from_caveset(native_bd_level.cave_nr,
+                                                          native_bd_level.level_nr);
+
+  // set better initial cave speed (to set better native replay tape length)
+  set_initial_cave_speed(native_bd_level.cave);
+
+  native_bd_level.loaded_from_caveset = TRUE;
+
+  // check if this cave has any replays
+  if (native_bd_level.cave->replays != NULL)
+  {
+    List *item = getNativeLevelReplay_BD(native_bd_level.cave->replays);
+
+    // check if any matching replay was found
+    if (item != NULL)
+      native_bd_level.replay = (GdReplay *)item->data;
+  }
+
+  return TRUE;
+}
+
+boolean SaveNativeLevel_BD(char *filename)
+{
+  GdCave *cave = gd_cave_new_from_cave(native_bd_level.cave);
+
+  gd_caveset_clear();
+  gd_caveset = list_append(gd_caveset, cave);
+
+  return gd_caveset_save_to_file(filename);
+}
+
+void DumpLevelset_BD(void)
+{
+  int num_levels_per_cave = (gd_caveset_has_levels() ? 5 : 1);
+
+  Print("Number of levels:   %d\n", num_levels_per_cave * gd_caveset_count());
+  Print("First level number: %d\n", 1);
+}
+
+
+// ============================================================================
+// game engine functions
+// ============================================================================
+
+int map_action_RND_to_BD(int action)
+{
+  GdDirection player_move = gd_direction_from_keypress(action & JOY_UP,
+                                                      action & JOY_DOWN,
+                                                      action & JOY_LEFT,
+                                                      action & JOY_RIGHT);
+  boolean player_fire = (action & (JOY_BUTTON_1 | JOY_BUTTON_2));
+
+  return (player_move | (player_fire ? GD_REPLAY_FIRE_MASK : 0));
+}
+
+int map_action_BD_to_RND(int action)
+{
+  GdDirection player_move = action & GD_REPLAY_MOVE_MASK;
+  boolean     player_fire = action & GD_REPLAY_FIRE_MASK;
+
+  int action_move = (player_move == GD_MV_UP           ? JOY_UP                :
+                    player_move == GD_MV_UP_RIGHT      ? JOY_UP   | JOY_RIGHT  :
+                    player_move == GD_MV_RIGHT         ?            JOY_RIGHT  :
+                    player_move == GD_MV_DOWN_RIGHT    ? JOY_DOWN | JOY_RIGHT  :
+                    player_move == GD_MV_DOWN          ? JOY_DOWN              :
+                    player_move == GD_MV_DOWN_LEFT     ? JOY_DOWN | JOY_LEFT   :
+                    player_move == GD_MV_LEFT          ?            JOY_LEFT   :
+                    player_move == GD_MV_UP_LEFT       ? JOY_UP   | JOY_LEFT   : JOY_NO_ACTION);
+  int action_fire = (player_fire ? JOY_BUTTON_1 : JOY_NO_ACTION);
+
+  return (action_move | action_fire);
+}
+
+boolean checkGameRunning_BD(void)
+{
+  return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING);
+}
+
+boolean checkGamePlaying_BD(void)
+{
+  return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CAVE_RUNNING &&
+         game_bd.game->cave != NULL && game_bd.game->cave->hatched);
+}
+
+boolean checkBonusTime_BD(void)
+{
+  return (game_bd.game != NULL && game_bd.game->state_counter == GAME_INT_CHECK_BONUS_TIME);
+}
+
+int getFramesPerSecond_BD(void)
+{
+  if (game_bd.game != NULL && game_bd.game->cave != NULL && game_bd.game->cave->pal_timing)
+    return FRAMES_PER_SECOND_NTSC;
+
+  return FRAMES_PER_SECOND_PAL;
+}
+
+int getTimeLeft_BD(void)
+{
+  if (game_bd.game != NULL && game_bd.game->cave != NULL)
+    return gd_cave_time_show(game_bd.game->cave, game_bd.game->cave->time);
+
+  return 0;
+}
+
+static void UpdateGameDoorValues_BD(void)
+{
+  GdCave *cave = game_bd.game->cave;
+  int time_secs = gd_cave_time_show(cave, cave->time);
+  int gems_still_needed = MAX(0, (cave->diamonds_needed - cave->diamonds_collected));
+
+  game_bd.time_played = time_secs;
+  game_bd.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_CountingScore = game_bd.score;
+  }
+}
+
+static void PrepareGameTileBitmap_BD(void)
+{
+  struct GraphicInfo_BD *g_template = &graphic_info_bd_color_template;
+  struct GraphicInfo_BD *g_default  = &graphic_info_bd_object[O_STONE][0];
+
+  // prepare bitmap using cave ready for playing (may have changed colors)
+  gd_prepare_tile_bitmap(game_bd.game->cave, g_template->bitmap, 1);
+
+  // set reference bitmap which should be replaced with prepared bitmap
+  gd_set_tile_bitmap_reference(g_default->bitmap);
+}
+
+void PreparePreviewTileBitmap_BD(Bitmap *bitmap, int scale_down_factor)
+{
+  // prepare bitmap using cave from file (with originally defined colors)
+  gd_prepare_tile_bitmap(native_bd_level.cave, bitmap, scale_down_factor);
+}
+
+void SetPreviewTileBitmapReference_BD(Bitmap *bitmap)
+{
+  gd_set_tile_bitmap_reference(bitmap);
+}
+
+Bitmap *GetPreviewTileBitmap_BD(Bitmap *bitmap)
+{
+  return gd_get_tile_bitmap(bitmap);
+}
+
+unsigned int InitEngineRandom_BD(int seed)
+{
+  if (seed == NEW_RANDOMIZE)
+  {
+    // get randomly selected seed to render the cave
+    seed = gd_random_int_range(0, GD_CAVE_SEED_MAX);
+  }
+
+  game_bd.random_seed = seed;
+
+  return (unsigned int)seed;
+}
+
+void InitGameEngine_BD(void)
+{
+  game_bd.level_solved = 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;
+
+  if (game_bd.game != NULL)
+    gd_game_free(game_bd.game);
+
+  game_bd.game = gd_game_new(native_bd_level.cave_nr, native_bd_level.level_nr);
+
+  game_bd.game->itercycle = 0;
+  game_bd.game->itermax = 8;   // default; dynamically changed at runtime
+  game_bd.game->itermax_last = game_bd.game->itermax;
+
+  // default: start with completely covered playfield
+  int next_state = GAME_INT_START_UNCOVER + 1;
+
+  // when skipping uncovering, start with uncovered playfield
+  if (setup.bd_skip_uncovering)
+    next_state = GAME_INT_LOAD_CAVE + 1;
+
+  // first iteration loads and prepares the cave (may change colors)
+  play_game_func(game_bd.game, 0);
+
+  // prepare tile bitmap with level-specific colors, if available
+  PrepareGameTileBitmap_BD();
+
+  // fast-forward game engine to selected state (covered or uncovered)
+  while (game_bd.game->state_counter < next_state)
+    play_game_func(game_bd.game, 0);
+
+  // 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())
+    game_bd.game->state_counter = GAME_INT_UNCOVER_ALL - 8;
+
+  if (setup.bd_skip_uncovering || isLevelEditorTestGame())
+    gd_scroll(game_bd.game, TRUE, TRUE);
+
+  ClearRectangle(gd_screen_bitmap, 0, 0, SXSIZE, SYSIZE);
+
+  RedrawPlayfield_BD(TRUE);
+
+  UpdateGameDoorValues_BD();
+}
+
+void GameActions_BD(byte action[MAX_PLAYERS])
+{
+  GdCave *cave = game_bd.game->cave;
+  boolean player_found = FALSE;
+  int player_x = 0;
+  int player_y = 0;
+  int x, y;
+
+  if (cave->getp)
+  {
+    for (y = 0; y < cave->h && !player_found; y++)
+    {
+      for (x = 0; x < cave->w && !player_found; x++)
+      {
+       int element = *cave->getp(cave, x, y);
+
+       if (element == O_PLAYER ||
+           element == O_PLAYER_BOMB ||
+           element == O_PLAYER_STIRRING ||
+           element == O_PLAYER_PNEUMATIC_LEFT ||
+           element == O_PLAYER_PNEUMATIC_RIGHT)
+       {
+         player_x = x;
+         player_y = y;
+
+         player_found = TRUE;
+       }
+      }
+    }
+  }
+
+  UpdateEngineValues(get_scroll_x(),
+                    get_scroll_y(),
+                    player_x,
+                    player_y);
+
+  if (setup.bd_skip_hatching && !game_bd.game->cave->hatched &&
+      game_bd.game->state_counter == GAME_INT_CAVE_RUNNING)
+  {
+    // fast-forward game engine until player hatched
+    while (!game_bd.game->cave->hatched)
+    {
+      play_game_func(game_bd.game, 0);
+
+      // also record or replay tape action during fast-forward
+      action = TapeCorrectAction_BD(action);
+    }
+  }
+
+  play_game_func(game_bd.game, action[0]);
+
+  // scroll without iterating engine if player out of sight (mainly due to wrap-around)
+  // (this is needed to prevent broken tapes in case of viewport or tile size changes)
+  while (game_bd.game->out_of_window)
+  {
+    RedrawPlayfield_BD(TRUE);
+
+    BlitScreenToBitmap_BD(backbuffer);
+
+    BackToFront();
+
+    play_game_func(game_bd.game, action[0]);
+  }
+
+  RedrawPlayfield_BD(FALSE);
+
+  UpdateGameDoorValues_BD();
+}
+
+
+// ============================================================================
+// graphics functions
+// ============================================================================
+
+// check if native BD graphics engine requested in custom graphics configuration
+boolean use_native_bd_graphics_engine(void)
+{
+  return game.use_native_bd_graphics_engine;
+}
+
+// check if smooth game element movements selected in setup menu
+boolean use_bd_smooth_movements(void)
+{
+  return ((setup.bd_smooth_movements == STATE_TRUE) ||
+         (setup.bd_smooth_movements == STATE_AUTO && !use_native_bd_graphics_engine()));
+}
+
+// check if player pushing graphics selected in setup menu
+boolean use_bd_pushing_graphics(void)
+{
+  return ((setup.bd_pushing_graphics == STATE_TRUE) ||
+         (setup.bd_pushing_graphics == STATE_AUTO && !use_native_bd_graphics_engine()));
+}
+
+// check if player up/down graphics selected in setup menu
+boolean use_bd_up_down_graphics(void)
+{
+  return ((setup.bd_up_down_graphics == STATE_TRUE) ||
+         (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)
+{
+  return ((setup.bd_skip_falling_sounds == STATE_TRUE) ||
+         (setup.bd_skip_falling_sounds == STATE_AUTO && !game.use_native_bd_sound_engine));
+}
+
+Bitmap **GetTitleScreenBitmaps_BD(void)
+{
+  Bitmap **title_screen_bitmaps = gd_get_title_screen_bitmaps();
+
+  if (title_screen_bitmaps == NULL || title_screen_bitmaps[0] == NULL)
+    return NULL;
+
+  return title_screen_bitmaps;
+}
+
+void CoverScreen_BD(void)
+{
+  game_bd.cover_screen = FALSE;
+
+  if (setup.bd_skip_uncovering)
+    return;
+
+  game_bd.game->state_counter = GAME_INT_COVER_START;
+
+  // play game engine (with normal speed) until cave covered
+  while (game_bd.game->state_counter < GAME_INT_COVER_ALL + 1)
+  {
+    play_game_func(game_bd.game, 0);
+
+    RedrawPlayfield_BD(TRUE);
+
+    BlitScreenToBitmap_BD(backbuffer);
+
+    BackToFront();
+  }
+
+  // stop uncovering loop sound when not using native sound engine
+  FadeSounds();
+}
+
+void BlitScreenToBitmap_BD(Bitmap *target_bitmap)
+{
+  GdCave *cave = native_bd_level.cave;
+  int xsize = SXSIZE;
+  int ysize = SYSIZE;
+  int full_xsize = (cave->x2 - cave->x1 + 1) * TILESIZE_VAR;
+  int full_ysize = (cave->y2 - cave->y1 + 1) * TILESIZE_VAR;
+  int sx = SX + (full_xsize < xsize ? (xsize - full_xsize) / 2 : 0);
+  int sy = SY + (full_ysize < ysize ? (ysize - full_ysize) / 2 : 0);
+  int sxsize = (full_xsize < xsize ? full_xsize : xsize);
+  int sysize = (full_ysize < ysize ? full_ysize : ysize);
+
+  BlitBitmap(gd_screen_bitmap, target_bitmap, 0, 0, sxsize, sysize, sx, sy);
+}
+
+void RedrawPlayfield_BD(boolean force_redraw)
+{
+  gd_drawcave(gd_screen_bitmap, game_bd.game, force_redraw);
+}
diff --git a/src/game_bd/main_bd.h b/src/game_bd/main_bd.h
new file mode 100644 (file)
index 0000000..8511f2e
--- /dev/null
@@ -0,0 +1,93 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main_bd.h
+// ============================================================================
+
+#ifndef MAIN_BD_H
+#define MAIN_BD_H
+
+// ============================================================================
+// external functions and definitions imported from main program to game_bd
+// ============================================================================
+
+#include "import_bd.h"
+
+
+// ============================================================================
+// functions and definitions that are exported from game_bd to main program
+// ============================================================================
+
+#include "export_bd.h"
+
+
+// ============================================================================
+// internal functions and definitions that are not exported to main program
+// ============================================================================
+
+#include "bd_bdcff.h"
+#include "bd_cave.h"
+#include "bd_cavedb.h"
+#include "bd_caveset.h"
+#include "bd_caveobject.h"
+#include "bd_caveengine.h"
+#include "bd_gameplay.h"
+#include "bd_c64import.h"
+#include "bd_graphics.h"
+#include "bd_colors.h"
+#include "bd_random.h"
+#include "bd_sound.h"
+
+
+// ----------------------------------------------------------------------------
+// constant definitions
+// ----------------------------------------------------------------------------
+
+// screen sizes and positions for BD engine
+
+#define TILESIZE               32
+
+extern int                     TILESIZE_VAR;
+
+#define TILEX                  TILESIZE_VAR
+#define TILEY                  TILESIZE_VAR
+
+extern int                     SCR_FIELDX, SCR_FIELDY;
+
+// often used screen positions
+
+extern int                     SX, SY;
+
+#define SXSIZE                 (SCR_FIELDX * TILEX)
+#define SYSIZE                 (SCR_FIELDY * TILEY)
+
+// compatibility macros
+
+#define gettext(String) (String)
+#define      N_(String) (String)
+#define       _(String) (String)
+
+#define STRUCT_MEMBER_P(struct_p, struct_offset)   \
+  ((void *) ((byte *) (struct_p) + (long) (struct_offset)))
+#define STRUCT_MEMBER(member_type, struct_p, struct_offset)   \
+  (*(member_type*) STRUCT_MEMBER_P ((struct_p), (struct_offset)))
+
+
+// ----------------------------------------------------------------------------
+// data structure definitions
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// exported variables
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// exported functions
+// ----------------------------------------------------------------------------
+
+#endif // MAIN_BD_H
index 827d51a339744eec6dcb4ab4a45129b0d5917827..d106dd03070bb8d6c36eda606162bd5763985fb8 100644 (file)
@@ -60,6 +60,9 @@ clean:
 depend:
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
+depend-clean:
+       $(RM) .depend
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
index 40b2dc6f90e6e6f9af864ed3a1c4c525aa180137..25d7785a0496ed761e14a989d031390cfac488e8 100644 (file)
@@ -126,7 +126,7 @@ boolean LoadNativeLevel_EM(char *filename, boolean level_info_only)
     return FALSE;
   }
 
-  file_version = cleanup_em_level(raw_leveldata, raw_leveldata_length,filename);
+  file_version = cleanup_em_level(raw_leveldata, raw_leveldata_length, filename);
 
   if (file_version == FILE_VERSION_EM_UNKNOWN)
   {
index 4c34fd16c7044d8a8b00ccca4fa1c10a8f3b0cd1..f8059b539e26169688a04c398952872597188d41 100644 (file)
@@ -472,6 +472,10 @@ void prepare_em_level(void)
   // - game_em.use_old_push_elements (default: FALSE)
   // - game_em.use_old_push_into_acid (default: FALSE)
   // - game_em.use_wrap_around (default: TRUE)
+  // - game_em.use_push_delay (default: TRUE)
+
+  if (native_em_level.file_version > FILE_VERSION_EM_V5)
+    game_em.use_push_delay = FALSE;
 
   game_em.level_solved = FALSE;
   game_em.game_over = FALSE;
diff --git a/src/game_em/export.h b/src/game_em/export.h
deleted file mode 100644 (file)
index c5373fd..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef EXPORT_H
-#define EXPORT_H
-
-// ============================================================================
-// functions and definitions exported from game_em to main program
-// ============================================================================
-
-#include "emerald.h"
-#include "cave.h"
-
-
-// ----------------------------------------------------------------------------
-// constant definitions
-// ----------------------------------------------------------------------------
-
-#define EM_MAX_CAVE_WIDTH              CAVE_WIDTH
-#define EM_MAX_CAVE_HEIGHT             CAVE_HEIGHT
-
-
-// ----------------------------------------------------------------------------
-// exported structures
-// ----------------------------------------------------------------------------
-
-struct GlobalInfo_EM
-{
-  Bitmap *screenbuffer;
-};
-
-struct GameInfo_EM
-{
-  unsigned int random;
-
-  boolean level_solved;
-  boolean game_over;
-
-  boolean any_player_moving;
-  boolean any_player_snapping;
-
-  int last_moving_player;
-  int last_player_direction[MAX_PLAYERS];
-
-  struct LOGIC *lev;
-  struct PLAYER *ply[MAX_PLAYERS];
-
-  // flags to handle bugs in and changes between different engine versions
-  boolean use_single_button;
-  boolean use_snap_key_bug;
-  boolean use_random_bug;
-  boolean use_old_explosions;
-  boolean use_old_android;
-  boolean use_old_push_elements;
-  boolean use_old_push_into_acid;
-  boolean use_wrap_around;
-};
-
-struct LevelInfo_EM
-{
-  int file_version;
-
-  struct CAVE *cav;
-};
-
-struct GraphicInfo_EM
-{
-  Bitmap *bitmap;
-  int src_x, src_y;
-  int src_offset_x, src_offset_y;
-  int dst_offset_x, dst_offset_y;
-  int width, height;
-
-  Bitmap *crumbled_bitmap;
-  int crumbled_src_x, crumbled_src_y;
-  int crumbled_border_size;
-  int crumbled_tile_size;
-
-  boolean has_crumbled_graphics;
-  boolean preserve_background;
-
-  int unique_identifier;       /* used to identify needed screen updates */
-};
-
-struct EngineSnapshotInfo_EM
-{
-  struct GameInfo_EM game_em;
-  struct LOGIC lev;
-  struct PLAYER ply[MAX_PLAYERS];
-
-  int frame;
-  int screen_x;
-  int screen_y;
-};
-
-
-// ----------------------------------------------------------------------------
-// exported functions
-// ----------------------------------------------------------------------------
-
-extern struct GlobalInfo_EM global_em_info;
-extern struct GameInfo_EM game_em;
-extern struct LevelInfo_EM native_em_level;
-extern struct GraphicInfo_EM graphic_info_em_object[GAME_TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][PLY_MAX][8];
-extern struct EngineSnapshotInfo_EM engine_snapshot_em;
-
-void em_open_all(void);
-void em_close_all(void);
-
-void InitGfxBuffers_EM(void);
-
-void InitGameEngine_EM(void);
-void GameActions_EM(byte *, boolean);
-
-unsigned int InitEngineRandom_EM(int);
-
-void setLevelInfoToDefaults_EM(void);
-boolean LoadNativeLevel_EM(char *, boolean);
-
-int getFieldbufferOffsetX_EM(void);
-int getFieldbufferOffsetY_EM(void);
-
-void BlitScreenToBitmap_EM(Bitmap *);
-void RedrawPlayfield_EM(boolean);
-
-void LoadEngineSnapshotValues_EM(void);
-void SaveEngineSnapshotValues_EM(void);
-
-boolean checkIfAllPlayersFitToScreen(void);
-
-int map_em_element_C_to_X(int);
-int map_em_element_X_to_C(int);
-
-#endif // EXPORT_H
diff --git a/src/game_em/export_em.h b/src/game_em/export_em.h
new file mode 100644 (file)
index 0000000..317b176
--- /dev/null
@@ -0,0 +1,144 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// export_em.h
+// ============================================================================
+
+#ifndef EXPORT_EM_H
+#define EXPORT_EM_H
+
+// ============================================================================
+// functions and definitions exported from game_em to main program
+// ============================================================================
+
+#include "emerald.h"
+#include "cave.h"
+
+
+// ----------------------------------------------------------------------------
+// constant definitions
+// ----------------------------------------------------------------------------
+
+#define EM_MAX_CAVE_WIDTH              CAVE_WIDTH
+#define EM_MAX_CAVE_HEIGHT             CAVE_HEIGHT
+
+
+// ----------------------------------------------------------------------------
+// exported structures
+// ----------------------------------------------------------------------------
+
+struct GlobalInfo_EM
+{
+  Bitmap *screenbuffer;
+};
+
+struct GameInfo_EM
+{
+  unsigned int random;
+
+  boolean level_solved;
+  boolean game_over;
+
+  boolean any_player_moving;
+  boolean any_player_snapping;
+
+  int last_moving_player;
+  int last_player_direction[MAX_PLAYERS];
+
+  struct LOGIC *lev;
+  struct PLAYER *ply[MAX_PLAYERS];
+
+  // flags to handle bugs in and changes between different engine versions
+  boolean use_single_button;
+  boolean use_snap_key_bug;
+  boolean use_random_bug;
+  boolean use_old_explosions;
+  boolean use_old_android;
+  boolean use_old_push_elements;
+  boolean use_old_push_into_acid;
+  boolean use_wrap_around;
+  boolean use_push_delay;
+};
+
+struct LevelInfo_EM
+{
+  int file_version;
+
+  struct CAVE *cav;
+};
+
+struct GraphicInfo_EM
+{
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int src_offset_x, src_offset_y;
+  int dst_offset_x, dst_offset_y;
+  int width, height;
+
+  Bitmap *crumbled_bitmap;
+  int crumbled_src_x, crumbled_src_y;
+  int crumbled_border_size;
+  int crumbled_tile_size;
+
+  boolean has_crumbled_graphics;
+  boolean preserve_background;
+
+  int unique_identifier;       // used to identify needed screen updates
+};
+
+struct EngineSnapshotInfo_EM
+{
+  struct GameInfo_EM game_em;
+  struct LOGIC lev;
+  struct PLAYER ply[MAX_PLAYERS];
+
+  int frame;
+  int screen_x;
+  int screen_y;
+};
+
+
+// ----------------------------------------------------------------------------
+// exported functions
+// ----------------------------------------------------------------------------
+
+extern struct GlobalInfo_EM global_em_info;
+extern struct GameInfo_EM game_em;
+extern struct LevelInfo_EM native_em_level;
+extern struct GraphicInfo_EM graphic_info_em_object[GAME_TILE_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][PLY_MAX][8];
+extern struct EngineSnapshotInfo_EM engine_snapshot_em;
+
+void em_open_all(void);
+void em_close_all(void);
+
+void InitGfxBuffers_EM(void);
+
+void InitGameEngine_EM(void);
+void GameActions_EM(byte[MAX_PLAYERS]);
+
+unsigned int InitEngineRandom_EM(int);
+
+void setLevelInfoToDefaults_EM(void);
+boolean LoadNativeLevel_EM(char *, boolean);
+
+int getFieldbufferOffsetX_EM(void);
+int getFieldbufferOffsetY_EM(void);
+
+void BlitScreenToBitmap_EM(Bitmap *);
+void RedrawPlayfield_EM(boolean);
+
+void LoadEngineSnapshotValues_EM(void);
+void SaveEngineSnapshotValues_EM(void);
+
+boolean checkIfAllPlayersFitToScreen(void);
+
+int map_em_element_C_to_X(int);
+int map_em_element_X_to_C(int);
+
+#endif // EXPORT_EM_H
index 8443ff0535dede2d67982d5150138b042a72ec00..a6a06800684ffe724ffe15fb40c11655180897d1 100644 (file)
@@ -82,7 +82,7 @@ void InitGameEngine_EM(void)
   RedrawPlayfield_EM(FALSE);
 }
 
-void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode)
+void GameActions_EM(byte action[MAX_PLAYERS])
 {
   int i;
   boolean any_player_dropping = FALSE;
@@ -109,7 +109,7 @@ void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode)
       any_player_dropping = TRUE;
 
   boolean single_step_mode_paused =
-    CheckSingleStepMode_EM(action, frame, game_em.any_player_moving,
+    CheckSingleStepMode_EM(frame, game_em.any_player_moving,
                           game_em.any_player_snapping, any_player_dropping);
 
   // draw wrapping around before going to single step pause mode
index 6f0904749b2c16feb705067b51944bd0287d562e..6b25a1f034d890b7c9abf203a380218cbb4a1ed5 100644 (file)
@@ -14,6 +14,7 @@
 
 #define GAME_EM_VERSION_1_0_0
 
-#include "export.h"
+#include "import_em.h"
+#include "export_em.h"
 
 #endif /* GAME_EM_H */
index 398ae6e0e303254f319e69931debc5d4b8b0b291..a3e941a56e7b5f77b0a75f0be73ddfabcceb39ed 100644 (file)
@@ -49,6 +49,14 @@ static int crumbled_state[MAX_PLAYFIELD_WIDTH + 2][MAX_PLAYFIELD_HEIGHT + 2];
 struct GraphicInfo_EM graphic_info_em_object[GAME_TILE_MAX][8];
 struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][PLY_MAX][8];
 
+static struct XY xy_topdown[] =
+{
+  {  0, -1 },
+  { -1,  0 },
+  { +1,  0 },
+  {  0, +1 }
+};
+
 static void setScreenCenteredToAllPlayers(int *, int *);
 
 int getFieldbufferOffsetX_EM(void)
@@ -301,13 +309,7 @@ static void animscreen(void)
   int x, y, i;
   int left = screen_x / TILEX;
   int top  = screen_y / TILEY;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   if (!game.use_native_emc_graphics_engine)
     for (y = lev.top; y < lev.bottom; y++)
@@ -333,8 +335,8 @@ static void animscreen(void)
       {
        for (i = 0; i < 4; i++)
        {
-         int xx = x + xy[i][0];
-         int yy = y + xy[i][1];
+         int xx = x + xy[i].x;
+         int yy = y + xy[i].y;
          int tile_next;
 
          if (xx < 0 || xx >= CAVE_BUFFER_WIDTH ||
diff --git a/src/game_em/import_em.h b/src/game_em/import_em.h
new file mode 100644 (file)
index 0000000..44e48c1
--- /dev/null
@@ -0,0 +1,46 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// import_em.h
+// ============================================================================
+
+#ifndef IMPORT_EM_H
+#define IMPORT_EM_H
+
+// ============================================================================
+// functions and definitions imported from main program to game_em
+// ============================================================================
+
+#include "../libgame/libgame.h"
+#include "../game.h"
+
+#include "export_em.h"
+
+
+// ----------------------------------------------------------------------------
+// imported functions
+// ----------------------------------------------------------------------------
+
+void UpdateEngineValues(int, int, int, int);
+
+boolean swapTiles_EM(boolean);
+boolean getTeamMode_EM(void);
+boolean isActivePlayer_EM(int);
+
+int getScreenFieldSizeX(void);
+int getScreenFieldSizeY(void);
+
+void PlayLevelSound_EM(int, int, int, int);
+void InitGraphicInfo_EM(void);
+boolean CheckSingleStepMode_EM(int, boolean, boolean, boolean);
+
+void SetGfxAnimation_EM(struct GraphicInfo_EM *, int, int, int, int);
+void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *, int, int, int, int);
+void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *, int, int, int);
+
+#endif // IMPORT_EM_H
index 1eaefcfc93421c0303f66dd66f7792a73c202206..b73edab2558584e6bc2d53475c04dd9aa81383b5 100644 (file)
@@ -293,7 +293,7 @@ static boolean player_killed(struct PLAYER *ply)
   if (!ply->alive)
     return FALSE;
 
-  if (lev.killed_out_of_time && setup.time_limit)
+  if (lev.killed_out_of_time && game.time_limit)
     return TRUE;
 
   switch (cave[x][y-1])
@@ -777,6 +777,9 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
        if (dy)
          break;
 
+       if (game_em.use_push_delay && RANDOM(32) < 16)
+         goto stone_push_anim;
+
        switch (cave[x+dx][y])
        {
           case Xblank:
@@ -817,6 +820,8 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
            break;
        }
 
+      stone_push_anim:
+
        ply->anim = PLY_push_n + anim;
        break;
 
@@ -824,6 +829,9 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
        if (dy)
          break;
 
+       if (game_em.use_push_delay && RANDOM(32) < 22)
+         goto bomb_push_anim;
+
        switch (cave[x+dx][y])
        {
          case Xblank:
@@ -864,6 +872,8 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
            break;
        }
 
+      bomb_push_anim:
+
        ply->anim = PLY_push_n + anim;
        break;
 
@@ -871,6 +881,9 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
        if (dy)
          break;
 
+       if (game_em.use_push_delay && RANDOM(32) < 19)
+         goto nut_push_anim;
+
        switch (cave[x+dx][y])
        {
           case Xblank:
@@ -911,6 +924,8 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
            break;
        }
 
+      nut_push_anim:
+
        ply->anim = PLY_push_n + anim;
        break;
 
@@ -1469,6 +1484,8 @@ static void check_player(struct PLAYER *ply)
 
   ply->dynamite_cnt = 0;       /* reset dynamite timer if we move */
 
+  seed = game_em.random;
+
   if (!ply->joy_snap)          /* player wants to move */
   {
     boolean moved = FALSE;
@@ -1500,6 +1517,8 @@ static void check_player(struct PLAYER *ply)
   {
     game_em.any_player_snapping = player_digfield(ply, dx, dy);
   }
+
+  game_em.random = seed;
 }
 
 static void set_nearest_player_xy(int x, int y, int *dx, int *dy)
index 84d5509ba327bcfcf02dd9719c7aadaeee9d80e5..3bbbcfe02e01208ca2c4628d763608c40c2baca9 100644 (file)
@@ -1,3 +1,14 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main_em.h
+// ============================================================================
+
 #ifndef MAIN_EM_H
 #define MAIN_EM_H
 
 // external functions and definitions imported from main program to game_em
 // ============================================================================
 
-#include "../engines.h"
+#include "import_em.h"
 
 
 // ============================================================================
 // functions and definitions that are exported from game_em to main program
 // ============================================================================
 
-#include "export.h"
+#include "export_em.h"
 
 
 // ============================================================================
 // constant definitions
 // ----------------------------------------------------------------------------
 
-/* values for native Emerald Mine game version */
+// values for native Emerald Mine game version
 #define FILE_VERSION_EM_UNKNOWN        0
 #define FILE_VERSION_EM_V1     1
 #define FILE_VERSION_EM_V2     2
 #define FILE_VERSION_EM_V3     3
-#define FILE_VERSION_EM_V4     4       /* (there really was no version 4) */
+#define FILE_VERSION_EM_V4     4       // (there really was no version 4)
 #define FILE_VERSION_EM_V5     5
 #define FILE_VERSION_EM_V6     6
 
 #define FILE_VERSION_EM_ACTUAL FILE_VERSION_EM_V6
 
-/* screen sizes and positions for EM engine */
+// screen sizes and positions for EM engine
 
 #define TILESIZE               32
 
@@ -51,14 +62,14 @@ extern int                  SCR_FIELDX, SCR_FIELDY;
 #define MAX_BUF_XSIZE          (SCR_FIELDX + 2 * CAVE_BUFFER_XOFFSET)
 #define MAX_BUF_YSIZE          (SCR_FIELDY + 2 * CAVE_BUFFER_YOFFSET)
 
-/* often used screen positions */
+// often used screen positions
 
 extern int                     SX, SY;
 
 #define SXSIZE                 (SCR_FIELDX * TILEX)
 #define SYSIZE                 (SCR_FIELDY * TILEY)
 
-/* other settings */
+// other settings
 #define PLAY_ELEMENT_SOUND     FALSE
 
 
index dfa293a6ebe1eeee4d905142e7af8a0618bb9db0..48eb9121c9dfabff3a301a53cdc7fc335d3513f5 100644 (file)
@@ -801,7 +801,7 @@ if(len >= 2110 && (buf[2106] == 255 && buf[2107] == 53 && buf[2108] == 48 && buf
 if(len >= 2106 && (buf[1983] == 116 || buf[2047] == 116)) // v4
 if(len >= 2106 && (buf[1983] == 27 || buf[2047] == 219)) // v3
 
-buf[0]=241;buf[1]=248;for(i=0,j=101;i<2106;i++,j+=7)buf[i]=(buf[i]^j)-17; // decrypt
+buf[0] = 241; buf[1] = 248; for(i = 0, j = 101; i < 2106; i++, j += 7) buf[i] = (buf[i] ^ j) - 17; // decrypt
 
 number of movements (calls to logic) = time * 50 / 8
 
index e3dba14067b2afd0eb079c0b451066831470664b..c979def407126aeabc56aa93dcfa241675a1057a 100644 (file)
@@ -57,6 +57,9 @@ clean:
 depend:
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
+depend-clean:
+       $(RM) .depend
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
diff --git a/src/game_mm/export.h b/src/game_mm/export.h
deleted file mode 100644 (file)
index 4a63b24..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-#ifndef GAME_MM_EXPORT_H
-#define GAME_MM_EXPORT_H
-
-// ============================================================================
-// functions and definitions exported from game_mm to main program
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// constant definitions
-// ----------------------------------------------------------------------------
-
-#define MM_MAX_PLAYFIELD_WIDTH         MAX_PLAYFIELD_WIDTH
-#define MM_MAX_PLAYFIELD_HEIGHT                MAX_PLAYFIELD_HEIGHT
-
-#define MM_STD_PLAYFIELD_WIDTH         16
-#define MM_STD_PLAYFIELD_HEIGHT                12
-
-#define MM_MAX_PLAYFIELD_SIZE          (MM_MAX_PLAYFIELD_WIDTH *       \
-                                        MM_MAX_PLAYFIELD_HEIGHT)
-
-#define MAX_NUM_AMOEBA                 100
-#define MAX_NUM_BEAMERS                        8
-
-#define MAX_LASER_LEN                  256
-#define MAX_LASER_ENERGY               100
-#define MAX_LASER_OVERLOAD             100
-
-#define MM_LEVEL_SCORE_ELEMENTS                16
-
-#define MM_MAX_LEVEL_NAME_LEN          32
-#define MM_MAX_LEVEL_AUTHOR_LEN                32
-
-
-#define EL_MM_START_1_NATIVE           0
-#define EL_MM_END_1_NATIVE             155
-
-#define EL_MM_CHAR_START_NATIVE                160
-#define EL_MM_CHAR_END_NATIVE          239
-
-#define EL_MM_START_2_NATIVE           240
-#define EL_MM_END_2_NATIVE             430
-
-#define EL_MM_RUNTIME_START_NATIVE     500
-#define EL_MM_RUNTIME_END_NATIVE       504
-
-#define EL_MM_DUMMY_START_NATIVE       700
-#define EL_MM_DUMMY_END_NATIVE         709
-
-// elements to be specially mapped
-#define EL_MM_EMPTY_NATIVE             0
-#define EL_DF_EMPTY_NATIVE             304
-
-// sounds
-#define SND_MM_GAME_LEVELTIME_CHARGING 0
-#define SND_MM_GAME_HEALTH_CHARGING    1
-
-
-// ----------------------------------------------------------------------------
-// data structure definitions
-// ----------------------------------------------------------------------------
-
-struct CycleList
-{
-  int x, y;
-  int steps;
-};
-
-struct MovingList
-{
-  int x, y;
-  int dir;
-};
-
-struct DamageList
-{
-  int x, y;
-  int edge, angle;
-  boolean is_mirror;
-};
-
-struct BeamerInfo
-{
-  int x, y;
-  int num;
-};
-
-struct PacMan
-{
-  int XP, YP;
-  int Dr;
-};
-
-struct LaserInfo
-{
-  struct XY start_edge;
-  int start_angle;
-
-  int current_angle;
-
-  struct DamageList damage[MAX_LASER_LEN + 10];
-  int num_damages;
-
-  struct XY edge[MAX_LASER_LEN + 10];
-  int num_edges;
-
-  struct BeamerInfo beamer[MAX_NUM_BEAMERS][2];
-  int beamer_edge[MAX_NUM_BEAMERS];
-  int beamer_nr[MAX_NUM_BEAMERS];
-  int num_beamers;
-
-  boolean overloaded;
-  int overload_value;
-
-  boolean fuse_off;
-  int fuse_x, fuse_y;
-
-  int dest_element;
-  boolean stops_inside_element;
-
-  boolean redraw;
-
-  int wall_mask;
-};
-
-struct GameInfo_MM
-{
-  boolean LevelSolved;
-  boolean GameOver;
-
-  struct CycleList cycle[MM_MAX_PLAYFIELD_SIZE];
-  int num_cycle;
-
-  struct MovingList pacman[MM_MAX_PLAYFIELD_SIZE];
-  int num_pacman;
-
-  int score;
-  int energy_left;
-  int kettles_still_needed;
-  int lights_still_needed;
-  int num_keys;
-
-  boolean level_solved;
-  boolean game_over;
-  int game_over_cause;
-
-  boolean cheat_no_overload;
-  boolean cheat_no_explosion;
-
-  int laser_overload_value;
-  boolean laser_enabled;
-};
-
-struct LevelInfo_MM
-{
-  int file_version;            // version of file the level was stored with
-  int game_version;            // version of game engine to play this level
-  boolean encoding_16bit_field;                // level contains 16-bit elements
-
-  int fieldx;
-  int fieldy;
-  int time;
-  int kettles_needed;
-  boolean auto_count_kettles;
-  boolean laser_red, laser_green, laser_blue;
-  char name[MM_MAX_LEVEL_NAME_LEN + 1];
-  char author[MM_MAX_LEVEL_AUTHOR_LEN + 1];
-  int score[MM_LEVEL_SCORE_ELEMENTS];
-  int amoeba_speed;
-  int time_fuse;
-  int time_bomb;
-  int time_ball;
-  int time_block;
-
-  short field[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-};
-
-struct EngineSnapshotInfo_MM
-{
-  struct GameInfo_MM game_mm;
-
-  struct LaserInfo laser;
-
-  short Ur[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-  short Hit[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-  short Box[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-  short Angle[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-  short Frame[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
-
-  short LX,LY, XS,YS, ELX,ELY;
-  short CT,Ct;
-
-  int last_LX, last_LY, last_hit_mask;
-  int hold_x, hold_y;
-  int pacman_nr;
-
-  unsigned int rotate_delay;
-  unsigned int pacman_delay;
-  unsigned int energy_delay;
-  unsigned int overload_delay;
-};
-
-
-// ----------------------------------------------------------------------------
-// exported functions
-// ----------------------------------------------------------------------------
-
-extern struct GameInfo_MM game_mm;
-extern struct LevelInfo_MM native_mm_level;
-extern struct EngineSnapshotInfo_MM engine_snapshot_mm;
-
-extern short Ur[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT];
-
-void mm_open_all(void);
-void mm_close_all(void);
-
-void InitElementProperties_MM(void);
-
-void InitGfxBuffers_MM(void);
-
-void InitGameEngine_MM(void);
-void InitGameActions_MM(void);
-void GameActions_MM(struct MouseActionInfo, boolean);
-
-void DrawLaser_MM(void);
-void DrawTileCursor_MM(int, boolean);
-
-boolean ClickElement(int, int, int);
-
-unsigned int InitEngineRandom_MM(int);
-
-void setLevelInfoToDefaults_MM(void);
-void copyInternalEngineVars_MM(void);
-boolean LoadNativeLevel_MM(char *, boolean);
-void SaveNativeLevel_MM(char *);
-
-int getFieldbufferOffsetX_MM(void);
-int getFieldbufferOffsetY_MM(void);
-
-void BlitScreenToBitmap_MM(Bitmap *);
-void RedrawPlayfield_MM(void);
-
-void LoadEngineSnapshotValues_MM(void);
-void SaveEngineSnapshotValues_MM(ListNode **);
-
-int getButtonFromTouchPosition(int, int, int, int);
-
-#endif // GAME_MM_EXPORT_H
diff --git a/src/game_mm/export_mm.h b/src/game_mm/export_mm.h
new file mode 100644 (file)
index 0000000..47ced95
--- /dev/null
@@ -0,0 +1,278 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// export_mm.h
+// ============================================================================
+
+#ifndef EXPORT_MM_H
+#define EXPORT_MM_H
+
+// ============================================================================
+// functions and definitions exported from game_mm to main program
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// constant definitions
+// ----------------------------------------------------------------------------
+
+#define MM_MAX_PLAYFIELD_WIDTH         MAX_PLAYFIELD_WIDTH
+#define MM_MAX_PLAYFIELD_HEIGHT                MAX_PLAYFIELD_HEIGHT
+
+#define MM_STD_PLAYFIELD_WIDTH         16
+#define MM_STD_PLAYFIELD_HEIGHT                12
+
+#define MM_MAX_PLAYFIELD_SIZE          (MM_MAX_PLAYFIELD_WIDTH *       \
+                                        MM_MAX_PLAYFIELD_HEIGHT)
+
+#define MAX_NUM_AMOEBA                 100
+#define MAX_NUM_BEAMERS                        8
+
+#define MAX_LASER_LEN                  256
+#define MAX_LASER_ENERGY               100
+#define MAX_LASER_OVERLOAD             100
+
+#define MM_LEVEL_SCORE_ELEMENTS                16
+
+#define MM_MAX_BALL_CONTENTS           16
+
+#define MM_MAX_LEVEL_NAME_LEN          32
+#define MM_MAX_LEVEL_AUTHOR_LEN                32
+
+
+#define EL_MM_START_1_NATIVE           0
+#define EL_MM_END_1_NATIVE             159
+
+#define EL_MM_CHAR_START_NATIVE                160
+#define EL_MM_CHAR_END_NATIVE          239
+
+#define EL_MM_START_2_NATIVE           240
+#define EL_MM_END_2_NATIVE             430
+
+#define EL_MM_START_3_NATIVE           431
+#define EL_MM_END_3_NATIVE             450
+
+#define EL_MM_RUNTIME_START_NATIVE     500
+#define EL_MM_RUNTIME_END_NATIVE       504
+
+// elements to be specially mapped
+#define EL_MM_EMPTY_NATIVE             0
+#define EL_DF_EMPTY_NATIVE             304
+
+// sounds
+#define SND_MM_GAME_LEVELTIME_CHARGING 0
+#define SND_MM_GAME_HEALTH_CHARGING    1
+
+
+// ----------------------------------------------------------------------------
+// data structure definitions
+// ----------------------------------------------------------------------------
+
+struct CycleList
+{
+  int x, y;
+  int steps;
+};
+
+struct MovingList
+{
+  int x, y;
+  int dir;
+};
+
+struct DamageList
+{
+  int x, y;
+  int edge, angle;
+  boolean is_mirror;
+};
+
+struct BeamerInfo
+{
+  int x, y;
+  int num;
+};
+
+struct PacMan
+{
+  int XP, YP;
+  int Dr;
+};
+
+struct LaserInfo
+{
+  struct XY start_edge;
+  int start_angle;
+
+  int current_angle;
+
+  struct DamageList damage[MAX_LASER_LEN + 10];
+  int num_damages;
+
+  struct XY edge[MAX_LASER_LEN + 10];
+  int num_edges;
+
+  struct BeamerInfo beamer[MAX_NUM_BEAMERS][2];
+  int beamer_edge[MAX_NUM_BEAMERS];
+  int beamer_nr[MAX_NUM_BEAMERS];
+  int num_beamers;
+
+  boolean overloaded;
+  int overload_value;
+
+  boolean fuse_off;
+  int fuse_x, fuse_y;
+
+  int dest_element;
+  int dest_element_last;
+  int dest_element_last_x;
+  int dest_element_last_y;
+  boolean stops_inside_element;
+
+  boolean redraw;
+
+  int wall_mask;
+};
+
+struct GameInfo_MM
+{
+  boolean LevelSolved;
+  boolean GameOver;
+
+  struct CycleList cycle[MM_MAX_PLAYFIELD_SIZE];
+  int num_cycle;
+
+  struct MovingList pacman[MM_MAX_PLAYFIELD_SIZE];
+  int num_pacman;
+
+  int score;
+  int energy_left;
+  int kettles_still_needed;
+  int lights_still_needed;
+  int num_keys;
+  int ball_choice_pos;         // current content element choice position
+  boolean laser_red, laser_green, laser_blue;
+
+  boolean has_mcduffin;
+  boolean level_solved;
+  boolean game_over;
+  int game_over_cause;
+  char *game_over_message;
+
+  boolean cheat_no_overload;
+  boolean cheat_no_explosion;
+
+  int laser_overload_value;
+  boolean laser_enabled;
+};
+
+struct LevelInfo_MM
+{
+  int file_version;            // version of file the level was stored with
+  int game_version;            // version of game engine to play this level
+  boolean encoding_16bit_field;                // level contains 16-bit elements
+
+  int fieldx;
+  int fieldy;
+  int time;
+  int kettles_needed;
+  boolean auto_count_kettles;
+  boolean mm_laser_red, mm_laser_green, mm_laser_blue;
+  boolean df_laser_red, df_laser_green, df_laser_blue;
+  char name[MM_MAX_LEVEL_NAME_LEN + 1];
+  char author[MM_MAX_LEVEL_AUTHOR_LEN + 1];
+  int score[MM_LEVEL_SCORE_ELEMENTS];
+  int amoeba_speed;
+  int time_fuse;
+  int time_bomb;
+  int time_ball;
+  int time_block;
+
+  int num_ball_contents;
+  int ball_choice_mode;
+  int ball_content[MM_MAX_BALL_CONTENTS];
+  boolean rotate_ball_content;
+  boolean explode_ball;
+
+  short field[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+};
+
+struct EngineSnapshotInfo_MM
+{
+  struct GameInfo_MM game_mm;
+
+  struct LaserInfo laser;
+
+  short Ur[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+  short Hit[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+  short Box[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+  short Angle[MAX_PLAYFIELD_WIDTH][MAX_PLAYFIELD_HEIGHT];
+
+  short LX, LY;
+  short XS, YS;
+  short ELX, ELY;
+  short CT, Ct;
+
+  int last_LX, last_LY, last_hit_mask;
+  int hold_x, hold_y;
+  int pacman_nr;
+
+  DelayCounter rotate_delay;
+  DelayCounter pacman_delay;
+  DelayCounter energy_delay;
+  DelayCounter overload_delay;
+};
+
+
+// ----------------------------------------------------------------------------
+// exported functions
+// ----------------------------------------------------------------------------
+
+extern struct GameInfo_MM game_mm;
+extern struct LevelInfo_MM native_mm_level;
+extern struct EngineSnapshotInfo_MM engine_snapshot_mm;
+
+extern short Ur[MM_MAX_PLAYFIELD_WIDTH][MM_MAX_PLAYFIELD_HEIGHT];
+
+void mm_open_all(void);
+
+void InitElementProperties_MM(void);
+
+void InitGfxBuffers_MM(void);
+
+void InitGameEngine_MM(void);
+void InitGameActions_MM(void);
+void GameActions_MM(struct MouseActionInfo);
+
+void DrawLaser_MM(void);
+void DrawTileCursor_MM(int, int, boolean);
+
+boolean ClickElement(int, int, int);
+
+unsigned int InitEngineRandom_MM(int);
+
+void setLevelInfoToDefaults_MM(void);
+void copyInternalEngineVars_MM(void);
+boolean LoadNativeLevel_MM(char *, boolean);
+void SaveNativeLevel_MM(char *);
+
+int getFieldbufferOffsetX_MM(void);
+int getFieldbufferOffsetY_MM(void);
+
+int getFlippedTileX_MM(int);
+int getFlippedTileY_MM(int);
+int getFlippedTileXY_MM(int);
+
+void BlitScreenToBitmap_MM(Bitmap *);
+void RedrawPlayfield_MM(void);
+
+void LoadEngineSnapshotValues_MM(void);
+void SaveEngineSnapshotValues_MM(void);
+
+int getButtonFromTouchPosition(int, int, int, int);
+
+#endif // EXPORT_MM_H
index 5655f322a7e9031cc42367631902593e3c6f2310..ccdbdf0d9725dd574c5df2b71e722514eeb0038a 100644 (file)
@@ -14,6 +14,7 @@
 
 #define GAME_MM_VERSION_1_0_0
 
-#include "export.h"
+#include "import_mm.h"
+#include "export_mm.h"
 
 #endif // GAME_MM_H
diff --git a/src/game_mm/import_mm.h b/src/game_mm/import_mm.h
new file mode 100644 (file)
index 0000000..07fe0ff
--- /dev/null
@@ -0,0 +1,52 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// import_mm.h
+// ============================================================================
+
+#ifndef IMPORT_MM_H
+#define IMPORT_MM_H
+
+// ============================================================================
+// functions and definitions imported from main program to game_mm
+// ============================================================================
+
+#include "../libgame/libgame.h"
+#include "../conf_gfx.h"
+#include "../game.h"
+
+#include "export_mm.h"
+
+
+// ----------------------------------------------------------------------------
+// imported functions
+// ----------------------------------------------------------------------------
+
+void SetDrawtoField(int);
+void BackToFront(void);
+
+int el2img_mm(int);
+int el_act2img_mm(int, int);
+
+void CheckSingleStepMode_MM(boolean, boolean);
+void ShowEnvelope(int);
+
+int getGraphicAnimationFrame(int, int);
+int getGraphicAnimationFrameXY(int, int, int);
+
+void getGraphicSource(int, int, Bitmap **, int *, int *);
+void getMiniGraphicSource(int, Bitmap **, int *, int *);
+void getSizedGraphicSource(int, int, int, Bitmap **, int *, int *);
+boolean getGraphicInfo_NewFrame(int, int, int);
+
+void AdvanceFrameCounter(void);
+void AdvanceGfxFrame(void);
+
+int getAnimationFrame(int, int, int, int, int);
+
+#endif // IMPORT_MM_H
index 27cec727328058423aa391aeb378faa2b492d908..c964a86f7dbb5c97410cdb62d40e378ec0bfae3d 100644 (file)
@@ -1,3 +1,14 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main_mm.h
+// ============================================================================
+
 #ifndef MAIN_MM_H
 #define MAIN_MM_H
 
 // external functions and definitions imported from main program to game_mm
 // ============================================================================
 
-#include "../engines.h"
-#include "../conf_gfx.h"
+#include "import_mm.h"
 
 
 // ============================================================================
 // functions and definitions that are exported from game_mm to main program
 // ============================================================================
 
-#include "export.h"
+#include "export_mm.h"
 
 
 // ============================================================================
@@ -35,6 +45,10 @@ extern int                   TILESIZE_VAR;
 #define TILEX_VAR              TILESIZE_VAR
 #define TILEY_VAR              TILESIZE_VAR
 
+#define MINI_TILESIZE          (TILESIZE / 2)
+#define MINI_TILEX             (TILEX / 2)
+#define MINI_TILEY             (TILEY / 2)
+
 extern int                     SCR_FIELDX, SCR_FIELDY;
 
 #define MAX_BUF_XSIZE          SCR_FIELDX
index 542c847db9e86c7d85d32fd37b6e2cbdd5be4ca9..4a85360925f4b409d969d114a3fca4718a6195ce 100644 (file)
@@ -112,9 +112,12 @@ void setLevelInfoToDefaults_MM(void)
   native_mm_level.time_bomb = 75;
   native_mm_level.time_ball = 75;
   native_mm_level.time_block = 75;
-  native_mm_level.laser_red = FALSE;
-  native_mm_level.laser_green = FALSE;
-  native_mm_level.laser_blue = TRUE;
+  native_mm_level.mm_laser_red = FALSE;
+  native_mm_level.mm_laser_green = FALSE;
+  native_mm_level.mm_laser_blue = TRUE;
+  native_mm_level.df_laser_red = TRUE;
+  native_mm_level.df_laser_green = TRUE;
+  native_mm_level.df_laser_blue = FALSE;
 
   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
     native_mm_level.name[i] = '\0';
@@ -127,6 +130,25 @@ void setLevelInfoToDefaults_MM(void)
   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
     native_mm_level.score[i] = 10;
 
+  int ball_content[] =
+  {
+    EL_MIRROR_START,
+    EL_MIRROR_FIXED_START,
+    EL_POLAR_START,
+    EL_POLAR_CROSS_START,
+    EL_PACMAN_START,
+    EL_KETTLE,
+    EL_BOMB,
+    EL_PRISM
+  };
+  int num_ball_contents = sizeof(ball_content) / sizeof(int);
+
+  native_mm_level.num_ball_contents = num_ball_contents;
+  native_mm_level.ball_choice_mode = ANIM_RANDOM;
+
+  for (i = 0; i < num_ball_contents; i++)
+    native_mm_level.ball_content[i] = ball_content[i];
+
   native_mm_level.field[0][0] = Ur[0][0] = EL_MCDUFFIN_RIGHT;
   native_mm_level.field[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
     Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
@@ -190,9 +212,9 @@ static int LoadLevel_MM_HEAD(File *file, int chunk_size,
     level->time_fuse = 25;
 
   laser_color                  = getFile8Bit(file);
-  level->laser_red             = (laser_color >> 2) & 0x01;
-  level->laser_green           = (laser_color >> 1) & 0x01;
-  level->laser_blue            = (laser_color >> 0) & 0x01;
+  level->mm_laser_red          = (laser_color >> 2) & 0x01;
+  level->mm_laser_green                = (laser_color >> 1) & 0x01;
+  level->mm_laser_blue         = (laser_color >> 0) & 0x01;
 
   level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
@@ -382,9 +404,9 @@ static void SaveLevel_MM_HEAD(FILE *file, struct LevelInfo_MM *level)
   fputc(level->amoeba_speed, file);
   fputc(level->time_fuse, file);
 
-  laser_color = ((level->laser_red   << 2) |
-                (level->laser_green << 1) |
-                (level->laser_blue  << 0));
+  laser_color = ((level->mm_laser_red   << 2) |
+                (level->mm_laser_green << 1) |
+                (level->mm_laser_blue  << 0));
   fputc(laser_color, file);
 
   fputc((level->encoding_16bit_field ? 1 : 0), file);
index 52f0b01e7d0c373a8d8ce012fbc71b2ca25a7824..20592f1b25b268e4603d002773cd71a4cd2b0724 100644 (file)
@@ -25,9 +25,8 @@
 
 // values for Explode_MM()
 #define EX_PHASE_START         0
-#define EX_NORMAL              0
-#define EX_KETTLE              1
-#define EX_SHORT               2
+#define EX_TYPE_NONE           0
+#define EX_TYPE_NORMAL         (1 << 0)
 
 // special positions in the game control window (relative to control window)
 #define XX_LEVEL               36
@@ -98,7 +97,22 @@ static void RaiseScoreElement_MM(int);
 static void RemoveMovingField_MM(int, int);
 static void InitMovingField_MM(int, int, int);
 static void ContinueMoving_MM(int, int);
-static void Moving2Blocked_MM(int, int, int *, int *);
+
+static void AddLaserEdge(int, int);
+static void ScanLaser(void);
+static void DrawLaser(int, int);
+static boolean HitElement(int, int);
+static boolean HitOnlyAnEdge(int);
+static boolean HitPolarizer(int, int);
+static boolean HitBlock(int, int);
+static boolean HitLaserSource(int, int);
+static boolean HitLaserDestination(int, int);
+static boolean HitReflectingWalls(int, int);
+static boolean HitAbsorbingWalls(int, int);
+static void RotateMirror(int, int, int);
+static boolean ObjHit(int, int, int);
+static void DeletePacMan(int, int);
+static void MovePacMen(void);
 
 // bitmap for laser beam detection
 static Bitmap *laser_bitmap = NULL;
@@ -111,13 +125,31 @@ static int hold_x = -1, hold_y = -1;
 static int pacman_nr = -1;
 
 // various game engine delay counters
-static unsigned int rotate_delay = 0;
-static unsigned int pacman_delay = 0;
-static unsigned int energy_delay = 0;
-static unsigned int overload_delay = 0;
+static DelayCounter rotate_delay = { AUTO_ROTATE_DELAY };
+static DelayCounter pacman_delay = { PACMAN_MOVE_DELAY };
+static DelayCounter energy_delay = { ENERGY_DELAY };
+static DelayCounter overload_delay = { 0 };
+
+// element mask positions for scanning pixels of MM elements
+#define MM_MASK_MCDUFFIN_RIGHT 0
+#define MM_MASK_MCDUFFIN_UP    1
+#define MM_MASK_MCDUFFIN_LEFT  2
+#define MM_MASK_MCDUFFIN_DOWN  3
+#define MM_MASK_GRID_1         4
+#define MM_MASK_GRID_2         5
+#define MM_MASK_GRID_3         6
+#define MM_MASK_GRID_4         7
+#define MM_MASK_SLOPE_1                8
+#define MM_MASK_SLOPE_2                9
+#define MM_MASK_SLOPE_3                10
+#define MM_MASK_SLOPE_4                11
+#define MM_MASK_RECTANGLE      12
+#define MM_MASK_CIRCLE         13
+
+#define NUM_MM_MASKS           14
 
 // element masks for scanning pixels of MM elements
-static const char mm_masks[10][16][16 + 1] =
+static const char mm_masks[NUM_MM_MASKS][16][16 + 1] =
 {
   {
     "                ",
@@ -263,6 +295,78 @@ static const char mm_masks[10][16][16 + 1] =
     "    XXX  XXXX   ",
     "     XX  XXXXX  ",
   },
+  {
+    "               X",
+    "              XX",
+    "             XXX",
+    "            XXXX",
+    "           XXXXX",
+    "          XXXXXX",
+    "         XXXXXXX",
+    "        XXXXXXXX",
+    "       XXXXXXXXX",
+    "      XXXXXXXXXX",
+    "     XXXXXXXXXXX",
+    "    XXXXXXXXXXXX",
+    "   XXXXXXXXXXXXX",
+    "  XXXXXXXXXXXXXX",
+    " XXXXXXXXXXXXXXX",
+    "XXXXXXXXXXXXXXXX",
+  },
+  {
+    "X               ",
+    "XX              ",
+    "XXX             ",
+    "XXXX            ",
+    "XXXXX           ",
+    "XXXXXX          ",
+    "XXXXXXX         ",
+    "XXXXXXXX        ",
+    "XXXXXXXXX       ",
+    "XXXXXXXXXX      ",
+    "XXXXXXXXXXX     ",
+    "XXXXXXXXXXXX    ",
+    "XXXXXXXXXXXXX   ",
+    "XXXXXXXXXXXXXX  ",
+    "XXXXXXXXXXXXXXX ",
+    "XXXXXXXXXXXXXXXX",
+  },
+  {
+    "XXXXXXXXXXXXXXXX",
+    "XXXXXXXXXXXXXXX ",
+    "XXXXXXXXXXXXXX  ",
+    "XXXXXXXXXXXXX   ",
+    "XXXXXXXXXXXX    ",
+    "XXXXXXXXXXX     ",
+    "XXXXXXXXXX      ",
+    "XXXXXXXXX       ",
+    "XXXXXXXX        ",
+    "XXXXXXX         ",
+    "XXXXXX          ",
+    "XXXXX           ",
+    "XXXX            ",
+    "XXX             ",
+    "XX              ",
+    "X               ",
+  },
+  {
+    "XXXXXXXXXXXXXXXX",
+    " XXXXXXXXXXXXXXX",
+    "  XXXXXXXXXXXXXX",
+    "   XXXXXXXXXXXXX",
+    "    XXXXXXXXXXXX",
+    "     XXXXXXXXXXX",
+    "      XXXXXXXXXX",
+    "       XXXXXXXXX",
+    "        XXXXXXXX",
+    "         XXXXXXX",
+    "          XXXXXX",
+    "           XXXXX",
+    "            XXXX",
+    "             XXX",
+    "              XX",
+    "               X",
+  },
   {
     "XXXXXXXXXXXXXXXX",
     "XXXXXXXXXXXXXXXX",
@@ -310,6 +414,8 @@ static int get_element_angle(int element)
       IS_LASER(element) ||
       IS_RECEIVER(element))
     return 4 * element_phase;
+  else if (IS_DF_SLOPE(element))
+    return 4 + (element_phase % 2) * 8;
   else
     return element_phase;
 }
@@ -335,7 +441,7 @@ static void DrawLaserLines(struct XY *points, int num_points, int mode)
   Pixel pixel_drawto = (mode == DL_LASER_ENABLED ? pen_ray     : pen_bg);
   Pixel pixel_buffer = (mode == DL_LASER_ENABLED ? WHITE_PIXEL : BLACK_PIXEL);
 
-  DrawLines(drawto, points, num_points, pixel_drawto);
+  DrawLines(drawto_mm, points, num_points, pixel_drawto);
 
   BEGIN_NO_HEADLESS
   {
@@ -411,6 +517,20 @@ static void CheckExitMM(void)
     PlayLevelSound_MM(exit_x, exit_y, exit_element, MM_ACTION_OPENING);
 }
 
+static void SetLaserColor(int brightness)
+{
+  int color_min = 0x00;
+  int color_max = brightness;          // (0x00 <= brightness <= 0xFF)
+  int color_up   = color_max * laser.overload_value / MAX_LASER_OVERLOAD;
+  int color_down = color_max - color_up;
+
+  pen_ray =
+    GetPixelFromRGB(window,
+                   (game_mm.laser_red   ? color_max  : color_up),
+                   (game_mm.laser_green ? color_down : color_min),
+                   (game_mm.laser_blue  ? color_down : color_min));
+}
+
 static void InitMovDir_MM(int x, int y)
 {
   int element = Tile[x][y];
@@ -448,7 +568,7 @@ static void InitField(int x, int y, boolean init_game)
 
     case EL_KETTLE:
     case EL_CELL:
-      if (native_mm_level.auto_count_kettles)
+      if (init_game && native_mm_level.auto_count_kettles)
        game_mm.kettles_still_needed++;
       break;
 
@@ -508,9 +628,27 @@ static void InitField(int x, int y, boolean init_game)
       }
       else if (IS_MCDUFFIN(element) || IS_LASER(element))
       {
-       laser.start_edge.x = x;
-       laser.start_edge.y = y;
-       laser.start_angle = get_element_angle(element);
+       if (init_game)
+       {
+         laser.start_edge.x = x;
+         laser.start_edge.y = y;
+         laser.start_angle = get_element_angle(element);
+       }
+
+        if (IS_MCDUFFIN(element))
+        {
+          game_mm.laser_red   = native_mm_level.mm_laser_red;
+          game_mm.laser_green = native_mm_level.mm_laser_green;
+          game_mm.laser_blue  = native_mm_level.mm_laser_blue;
+        }
+        else
+        {
+          game_mm.laser_red   = native_mm_level.df_laser_red;
+          game_mm.laser_green = native_mm_level.df_laser_green;
+          game_mm.laser_blue  = native_mm_level.df_laser_blue;
+        }
+
+       game_mm.has_mcduffin = (IS_MCDUFFIN(element));
       }
 
       break;
@@ -537,7 +675,6 @@ static void InitCycleElements_RotateSingleStep(void)
 
     Tile[x][y] = next_element;
 
-    DrawField_MM(x, y);
     game_mm.cycle[i].steps -= step;
   }
 }
@@ -574,10 +711,7 @@ static void InitLaser(void)
 
   AddLaserEdge(LX, LY);                // set laser starting edge
 
-  pen_ray = GetPixelFromRGB(window,
-                           native_mm_level.laser_red   * 0xFF,
-                           native_mm_level.laser_green * 0xFF,
-                           native_mm_level.laser_blue  * 0xFF);
+  SetLaserColor(0xFF);
 }
 
 void InitGameEngine_MM(void)
@@ -587,8 +721,8 @@ void InitGameEngine_MM(void)
   BEGIN_NO_HEADLESS
   {
     // initialize laser bitmap to current playfield (screen) size
-    ReCreateBitmap(&laser_bitmap, drawto->width, drawto->height);
-    ClearRectangle(laser_bitmap, 0, 0, drawto->width, drawto->height);
+    ReCreateBitmap(&laser_bitmap, drawto_mm->width, drawto_mm->height);
+    ClearRectangle(laser_bitmap, 0, 0, drawto_mm->width, drawto_mm->height);
   }
   END_NO_HEADLESS
 
@@ -602,10 +736,17 @@ void InitGameEngine_MM(void)
     (native_mm_level.auto_count_kettles ? 0 : native_mm_level.kettles_needed);
   game_mm.lights_still_needed = 0;
   game_mm.num_keys = 0;
+  game_mm.ball_choice_pos = 0;
+
+  game_mm.laser_red = FALSE;
+  game_mm.laser_green = FALSE;
+  game_mm.laser_blue = TRUE;
+  game_mm.has_mcduffin = TRUE;
 
   game_mm.level_solved = FALSE;
   game_mm.game_over = FALSE;
   game_mm.game_over_cause = 0;
+  game_mm.game_over_message = NULL;
 
   game_mm.laser_overload_value = 0;
   game_mm.laser_enabled = FALSE;
@@ -624,6 +765,9 @@ void InitGameEngine_MM(void)
   laser.fuse_x = laser.fuse_y = -1;
 
   laser.dest_element = EL_EMPTY;
+  laser.dest_element_last = EL_EMPTY;
+  laser.dest_element_last_x = -1;
+  laser.dest_element_last_y = -1;
   laser.wall_mask = 0;
 
   last_LX = 0;
@@ -637,10 +781,10 @@ void InitGameEngine_MM(void)
 
   CT = Ct = 0;
 
-  rotate_delay = 0;
-  pacman_delay = 0;
-  energy_delay = 0;
-  overload_delay = 0;
+  rotate_delay.count = 0;
+  pacman_delay.count = 0;
+  energy_delay.count = 0;
+  overload_delay.count = 0;
 
   ClickElement(-1, -1, -1);
 
@@ -653,7 +797,6 @@ void InitGameEngine_MM(void)
       Angle[x][y] = 0;
       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
       Store[x][y] = Store2[x][y] = 0;
-      Frame[x][y] = 0;
       Stop[x][y] = FALSE;
 
       InitField(x, y, TRUE);
@@ -691,16 +834,27 @@ void InitGameActions_MM(void)
       cycle_steps_done++;
     }
 
-    BackToFront();
+    AdvanceFrameCounter();
+    AdvanceGfxFrame();
 
-    ColorCycling();
+    if (PendingEscapeKeyEvent())
+      continue;
 
 #ifdef DEBUG
     if (setup.quick_doors)
       continue;
 #endif
+
+    DrawLevel_MM();
+
+    BackToFront_MM();
   }
 
+#ifdef DEBUG
+  if (setup.quick_doors)
+    DrawLevel_MM();
+#endif
+
   ScanLaser();
 
   if (game_mm.kettles_still_needed == 0)
@@ -708,14 +862,64 @@ void InitGameActions_MM(void)
 
   SetTileCursorXY(laser.start_edge.x, laser.start_edge.y);
   SetTileCursorActive(TRUE);
+
+  // restart all delay counters after initially cycling game elements
+  ResetFrameCounter(&rotate_delay);
+  ResetFrameCounter(&pacman_delay);
+  ResetFrameCounter(&energy_delay);
+  ResetFrameCounter(&overload_delay);
+}
+
+static void FadeOutLaser(void)
+{
+  int i;
+
+  for (i = 15; i >= 0; i--)
+  {
+    SetLaserColor(0x11 * i);
+
+    DrawLaser(0, DL_LASER_ENABLED);
+
+    BackToFront_MM();
+    Delay_WithScreenUpdates(50);
+  }
+
+  DrawLaser(0, DL_LASER_DISABLED);
+
+  StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
+}
+
+static void GameOver_MM(int game_over_cause)
+{
+  game_mm.game_over = TRUE;
+  game_mm.game_over_cause = game_over_cause;
+  game_mm.game_over_message = (game_mm.has_mcduffin ?
+                              (game_over_cause == GAME_OVER_BOMB ?
+                               "Bomb killed Mc Duffin!" :
+                               game_over_cause == GAME_OVER_NO_ENERGY ?
+                               "Out of magic energy!" :
+                               game_over_cause == GAME_OVER_OVERLOADED ?
+                               "Magic spell hit Mc Duffin!" :
+                               NULL) :
+                              (game_over_cause == GAME_OVER_BOMB ?
+                               "Bomb destroyed laser cannon!" :
+                               game_over_cause == GAME_OVER_NO_ENERGY ?
+                               "Out of laser energy!" :
+                               game_over_cause == GAME_OVER_OVERLOADED ?
+                               "Laser beam hit laser cannon!" :
+                               NULL));
+
+  SetTileCursorActive(FALSE);
 }
 
-void AddLaserEdge(int lx, int ly)
+static void AddLaserEdge(int lx, int ly)
 {
-  int clx = dSX + lx;
-  int cly = dSY + ly;
+  int full_sxsize = MAX(FULL_SXSIZE, lev_fieldx * TILEX);
+  int full_sysize = MAX(FULL_SYSIZE, lev_fieldy * TILEY);
 
-  if (clx < -2 || cly < -2 || clx >= SXSIZE + 2 || cly >= SYSIZE + 2)
+  // check if laser is still inside visible playfield area (or inside level)
+  if (cSX + lx < REAL_SX || cSX + lx >= REAL_SX + full_sxsize ||
+      cSY + ly < REAL_SY || cSY + ly >= REAL_SY + full_sysize)
   {
     Warn("AddLaserEdge: out of bounds: %d, %d", lx, ly);
 
@@ -729,8 +933,15 @@ void AddLaserEdge(int lx, int ly)
   laser.redraw = TRUE;
 }
 
-void AddDamagedField(int ex, int ey)
+static void AddDamagedField(int ex, int ey)
 {
+  // prevent adding the same field position again
+  if (laser.num_damages > 0 &&
+      laser.damage[laser.num_damages - 1].x == ex &&
+      laser.damage[laser.num_damages - 1].y == ey &&
+      laser.damage[laser.num_damages - 1].edge == laser.num_edges)
+    return;
+
   laser.damage[laser.num_damages].is_mirror = FALSE;
   laser.damage[laser.num_damages].angle = laser.current_angle;
   laser.damage[laser.num_damages].edge = laser.num_edges;
@@ -756,14 +967,33 @@ static boolean StepBehind(void)
 
 static int getMaskFromElement(int element)
 {
-  if (IS_GRID(element))
-    return IMG_MM_MASK_GRID_1 + get_element_phase(element);
-  else if (IS_MCDUFFIN(element))
-    return IMG_MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element);
-  else if (IS_RECTANGLE(element) || IS_DF_GRID(element))
-    return IMG_MM_MASK_RECTANGLE;
+  if (IS_MCDUFFIN(element))
+    return MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element);
+  else if (IS_GRID(element))
+    return MM_MASK_GRID_1 + get_element_phase(element);
+  else if (IS_DF_GRID(element))
+    return MM_MASK_RECTANGLE;
+  else if (IS_DF_SLOPE(element))
+    return MM_MASK_SLOPE_1 + get_element_phase(element);
+  else if (IS_RECTANGLE(element))
+    return MM_MASK_RECTANGLE;
   else
-    return IMG_MM_MASK_CIRCLE;
+    return MM_MASK_CIRCLE;
+}
+
+static int getPixelFromMask(int pos, int dx, int dy)
+{
+  return (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0);
+}
+
+static int getLevelFromLaserX(int x)
+{
+  return x / TILEX - (x < 0 ? 1 : 0);          // correct negative values
+}
+
+static int getLevelFromLaserY(int y)
+{
+  return y / TILEY - (y < 0 ? 1 : 0);          // correct negative values
 }
 
 static int ScanPixel(void)
@@ -791,14 +1021,34 @@ static int ScanPixel(void)
     }
 #endif
 
+    // check if laser scan has crossed element boundaries (not just mini tiles)
+    boolean cross_x = (LX / TILEX != (LX + 2) / TILEX);
+    boolean cross_y = (LY / TILEY != (LY + 2) / TILEY);
+
+    if (cross_x && cross_y)
+    {
+      int elx1 = (LX - XS) / TILEX;
+      int ely1 = (LY + YS) / TILEY;
+      int elx2 = (LX + XS) / TILEX;
+      int ely2 = (LY - YS) / TILEY;
+
+      // add element corners left and right from the laser beam to damage list
+
+      if (IN_LEV_FIELD(elx1, ely1) && Tile[elx1][ely1] != EL_EMPTY)
+       AddDamagedField(elx1, ely1);
+
+      if (IN_LEV_FIELD(elx2, ely2) && Tile[elx2][ely2] != EL_EMPTY)
+       AddDamagedField(elx2, ely2);
+    }
+
     for (i = 0; i < 4; i++)
     {
       int px = LX + (i % 2) * 2;
       int py = LY + (i / 2) * 2;
       int dx = px % TILEX;
       int dy = py % TILEY;
-      int lx = (px + TILEX) / TILEX - 1;  // ...+TILEX...-1 to get correct
-      int ly = (py + TILEY) / TILEY - 1;  // negative values!
+      int lx = getLevelFromLaserX(px);
+      int ly = getLevelFromLaserY(py);
       Pixel pixel;
 
       if (IN_LEV_FIELD(lx, ly))
@@ -817,13 +1067,14 @@ static int ScanPixel(void)
        }
        else
        {
-         int pos = getMaskFromElement(element) - IMG_MM_MASK_MCDUFFIN_RIGHT;
+         int pos = getMaskFromElement(element);
 
-         pixel = (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0);
+         pixel = getPixelFromMask(pos, dx, dy);
        }
       }
       else
       {
+       // check if laser is still inside visible playfield area
        pixel = (cSX + px < REAL_SX || cSX + px >= REAL_SX + FULL_SXSIZE ||
                 cSY + py < REAL_SY || cSY + py >= REAL_SY + FULL_SYSIZE);
       }
@@ -843,15 +1094,46 @@ static int ScanPixel(void)
   return hit_mask;
 }
 
-void ScanLaser(void)
+static void DeactivateLaserTargetElement(void)
 {
-  int element;
+  if (laser.dest_element_last == EL_BOMB_ACTIVE ||
+      laser.dest_element_last == EL_MINE_ACTIVE ||
+      laser.dest_element_last == EL_GRAY_BALL_ACTIVE ||
+      laser.dest_element_last == EL_GRAY_BALL_OPENING)
+  {
+    int x = laser.dest_element_last_x;
+    int y = laser.dest_element_last_y;
+    int element = laser.dest_element_last;
+
+    if (Tile[x][y] == element)
+      Tile[x][y] = (element == EL_BOMB_ACTIVE ? EL_BOMB :
+                   element == EL_MINE_ACTIVE ? EL_MINE : EL_GRAY_BALL);
+
+    if (Tile[x][y] == EL_GRAY_BALL)
+      MovDelay[x][y] = 0;
+
+    laser.dest_element_last = EL_EMPTY;
+    laser.dest_element_last_x = -1;
+    laser.dest_element_last_y = -1;
+  }
+}
+
+static void ScanLaser(void)
+{
+  int element = EL_EMPTY;
+  int last_element = EL_EMPTY;
   int end = 0, rf = laser.num_edges;
 
   // do not scan laser again after the game was lost for whatever reason
   if (game_mm.game_over)
     return;
 
+  // do not scan laser if fuse is off
+  if (laser.fuse_off)
+    return;
+
+  DeactivateLaserTargetElement();
+
   laser.overloaded = FALSE;
   laser.stops_inside_element = FALSE;
 
@@ -883,41 +1165,92 @@ void ScanLaser(void)
          LX, LY, XS, YS);
 #endif
 
-    // hit something -- check out what it was
-    ELX = (LX + XS) / TILEX;
-    ELY = (LY + YS) / TILEY;
+    // check if laser scan has hit two diagonally adjacent element corners
+    boolean diag_1 = ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1);
+    boolean diag_2 = ((hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2);
+
+    // check if laser scan has crossed element boundaries (not just mini tiles)
+    boolean cross_x = (getLevelFromLaserX(LX) != getLevelFromLaserX(LX + 2));
+    boolean cross_y = (getLevelFromLaserY(LY) != getLevelFromLaserY(LY + 2));
+
+    if (cross_x || cross_y)
+    {
+      // hit something at next tile -- check out what it was
+      ELX = getLevelFromLaserX(LX + XS);
+      ELY = getLevelFromLaserY(LY + YS);
+    }
+    else
+    {
+      // hit something at same tile -- check out what it was
+      ELX = getLevelFromLaserX(LX);
+      ELY = getLevelFromLaserY(LY);
+    }
 
 #if 0
     Debug("game:mm:ScanLaser", "hit_mask (1) == '%x' (%d, %d) (%d, %d)",
          hit_mask, LX, LY, ELX, ELY);
 #endif
 
-    if (!IN_LEV_FIELD(ELX, ELY) || !IN_PIX_FIELD(LX, LY))
+    if (!IN_LEV_FIELD(ELX, ELY))
     {
+      // laser next step position
+      int x = cSX + LX + XS;
+      int y = cSY + LY + YS;
+
+      // check if next step of laser is still inside visible playfield area
+      if (x >= REAL_SX && x < REAL_SX + FULL_SXSIZE &&
+         y >= REAL_SY && y < REAL_SY + FULL_SYSIZE)
+      {
+       // go on with another step
+       LX += XS;
+       LY += YS;
+
+       continue;
+      }
+
       element = EL_EMPTY;
       laser.dest_element = element;
 
       break;
     }
 
-    if (hit_mask == (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT))
+    // handle special case of laser hitting two diagonally adjacent elements
+    // (with or without a third corner element behind these two elements)
+    if ((diag_1 || diag_2) && cross_x && cross_y)
     {
-      /* we have hit the top-right and bottom-left element --
-        choose the bottom-left one */
-      /* !!! THIS CAN BE DONE MORE INTELLIGENTLY, FOR EXAMPLE, IF ONE
-        ELEMENT WAS STEEL AND THE OTHER ONE WAS ICE => ALWAYS CHOOSE
-        THE ICE AND MELT IT AWAY INSTEAD OF OVERLOADING LASER !!! */
-      ELX = (LX - 2) / TILEX;
-      ELY = (LY + 2) / TILEY;
-    }
+      // compare the two diagonally adjacent elements
+      int xoffset = 2;
+      int yoffset = 2 * (diag_1 ? -1 : +1);
+      int elx1 = (LX - xoffset) / TILEX;
+      int ely1 = (LY + yoffset) / TILEY;
+      int elx2 = (LX + xoffset) / TILEX;
+      int ely2 = (LY - yoffset) / TILEY;
+      int e1 = Tile[elx1][ely1];
+      int e2 = Tile[elx2][ely2];
+      boolean use_element_1 = FALSE;
+
+      if (IS_WALL_ICE(e1) || IS_WALL_ICE(e2))
+      {
+       if (IS_WALL_ICE(e1) && IS_WALL_ICE(e2))
+         use_element_1 = (RND(2) ? TRUE : FALSE);
+       else if (IS_WALL_ICE(e1))
+         use_element_1 = TRUE;
+      }
+      else if (IS_WALL_AMOEBA(e1) || IS_WALL_AMOEBA(e2))
+      {
+       // if both tiles match, we can just select the first one
+       if (IS_WALL_AMOEBA(e1))
+         use_element_1 = TRUE;
+      }
+      else if (IS_ABSORBING_BLOCK(e1) || IS_ABSORBING_BLOCK(e2))
+      {
+       // if both tiles match, we can just select the first one
+       if (IS_ABSORBING_BLOCK(e1))
+         use_element_1 = TRUE;
+      }
 
-    if (hit_mask == (HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT))
-    {
-      /* we have hit the top-left and bottom-right element --
-        choose the top-left one */
-      // !!! SEE ABOVE !!!
-      ELX = (LX - 2) / TILEX;
-      ELY = (LY - 2) / TILEY;
+      ELX = (use_element_1 ? elx1 : elx2);
+      ELY = (use_element_1 ? ely1 : ely2);
     }
 
 #if 0
@@ -925,6 +1258,8 @@ void ScanLaser(void)
          hit_mask, LX, LY, ELX, ELY);
 #endif
 
+    last_element = element;
+
     element = Tile[ELX][ELY];
     laser.dest_element = element;
 
@@ -943,9 +1278,15 @@ void ScanLaser(void)
            ELX, ELY, element);
 #endif
 
+    // special case: leaving fixed MM steel grid (upwards) with non-90° angle
+    if (element == EL_EMPTY &&
+       IS_GRID_STEEL(last_element) &&
+       laser.current_angle % 4)                // angle is not 90°
+      element = last_element;
+
     if (element == EL_EMPTY)
     {
-      if (!HitOnlyAnEdge(element, hit_mask))
+      if (!HitOnlyAnEdge(hit_mask))
        break;
     }
     else if (element == EL_FUSE_ON)
@@ -1001,6 +1342,14 @@ void ScanLaser(void)
     if (rf)
       DrawLaser(rf - 1, DL_LASER_ENABLED);
     rf = laser.num_edges;
+
+    if (!IS_DF_WALL_STEEL(element))
+    {
+      // only used for scanning DF steel walls; reset for all other elements
+      last_LX = 0;
+      last_LY = 0;
+      last_hit_mask = 0;
+    }
   }
 
 #if 0
@@ -1035,6 +1384,22 @@ void ScanLaser(void)
 #endif
 }
 
+static void ScanLaser_FromLastMirror(void)
+{
+  int start_pos = (laser.num_damages > 0 ? laser.num_damages - 1 : 0);
+  int i;
+
+  for (i = start_pos; i >= 0; i--)
+    if (laser.damage[i].is_mirror)
+      break;
+
+  int start_edge = (i > 0 ? laser.damage[i].edge - 1 : 0);
+
+  DrawLaser(start_edge, DL_LASER_DISABLED);
+
+  ScanLaser();
+}
+
 static void DrawLaserExt(int start_edge, int num_edges, int mode)
 {
   int element;
@@ -1227,6 +1592,13 @@ static void DrawLaserExt(int start_edge, int num_edges, int mode)
 
 void DrawLaser(int start_edge, int mode)
 {
+  // do not draw laser if fuse is off
+  if (laser.fuse_off && mode == DL_LASER_ENABLED)
+    return;
+
+  if (mode == DL_LASER_DISABLED)
+    DeactivateLaserTargetElement();
+
   if (laser.num_edges - start_edge < 0)
   {
     Warn("DrawLaser: laser.num_edges - start_edge < 0");
@@ -1252,7 +1624,7 @@ void DrawLaser(int start_edge, int mode)
          continue;
 
 #if 0
-       Debug("game:mm:DrawLaser", "DL_LASER_ENABLED: i==%d: %d, %d",
+       Debug("game:mm:DrawLaser", "DL_LASER_ENABLED: i == %d: %d, %d",
              i, laser.beamer_edge[i], tmp_start_edge);
 #endif
 
@@ -1313,10 +1685,80 @@ void DrawLaser_MM(void)
   DrawLaser(0, game_mm.laser_enabled);
 }
 
-boolean HitElement(int element, int hit_mask)
+static boolean HitElement(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
-    return FALSE;
+  if (IS_DF_SLOPE(element))
+  {
+    // check if laser scan has crossed element boundaries (not just mini tiles)
+    boolean cross_x = (getLevelFromLaserX(LX) != getLevelFromLaserX(LX + 2));
+    boolean cross_y = (getLevelFromLaserY(LY) != getLevelFromLaserY(LY + 2));
+    int element_angle = get_element_angle(element);
+    int mirrored_angle = get_mirrored_angle(laser.current_angle, element_angle);
+    int opposite_angle = get_opposite_angle(laser.current_angle);
+
+    // check if wall (horizontal or vertical) side of slope was hit
+    if (hit_mask == HIT_MASK_LEFT ||
+       hit_mask == HIT_MASK_RIGHT ||
+       hit_mask == HIT_MASK_TOP ||
+       hit_mask == HIT_MASK_BOTTOM)
+    {
+      boolean hit_slope_corner_in_laser_direction =
+       ((hit_mask == HIT_MASK_LEFT   && (element == EL_DF_SLOPE_01 ||
+                                         element == EL_DF_SLOPE_02)) ||
+        (hit_mask == HIT_MASK_RIGHT  && (element == EL_DF_SLOPE_00 ||
+                                         element == EL_DF_SLOPE_03)) ||
+        (hit_mask == HIT_MASK_TOP    && (element == EL_DF_SLOPE_02 ||
+                                         element == EL_DF_SLOPE_03)) ||
+        (hit_mask == HIT_MASK_BOTTOM && (element == EL_DF_SLOPE_00 ||
+                                         element == EL_DF_SLOPE_01)));
+
+      boolean hit_slope_corner_in_laser_direction_double_checked =
+       (cross_x && cross_y &&
+        laser.current_angle == mirrored_angle &&
+        hit_slope_corner_in_laser_direction);
+
+      // check special case of laser hitting the corner of a slope and another
+      // element (either wall or another slope), following the diagonal side
+      // of the slope which has the same angle as the direction of the laser
+      if (!hit_slope_corner_in_laser_direction_double_checked)
+       return HitReflectingWalls(element, hit_mask);
+    }
+
+    // check if an edge was hit while crossing element borders
+    if (cross_x && cross_y && get_number_of_bits(hit_mask) == 1)
+    {
+      // check both sides of potentially diagonal side of slope
+      int dx1 = (LX + XS) % TILEX;
+      int dy1 = (LY + YS) % TILEY;
+      int dx2 = (LX + XS + 2) % TILEX;
+      int dy2 = (LY + YS + 2) % TILEY;
+      int pos = getMaskFromElement(element);
+
+      // check if we are entering empty space area after hitting edge
+      if (!getPixelFromMask(pos, dx1, dy1) &&
+         !getPixelFromMask(pos, dx2, dy2))
+      {
+       // we already know that we hit an edge, but use this function to go on
+       if (HitOnlyAnEdge(hit_mask))
+         return FALSE;
+      }
+    }
+
+    // check if laser is reflected by slope by 180°
+    if (mirrored_angle == opposite_angle)
+    {
+      AddDamagedField(LX / TILEX, LY / TILEY);
+
+      laser.overloaded = TRUE;
+
+      return TRUE;
+    }
+  }
+  else
+  {
+    if (HitOnlyAnEdge(hit_mask))
+      return FALSE;
+  }
 
   if (IS_MOVING(ELX, ELY) || IS_BLOCKED(ELX, ELY))
     element = MovingOrBlocked2Element_MM(ELX, ELY);
@@ -1336,23 +1778,35 @@ boolean HitElement(int element, int hit_mask)
 
   AddDamagedField(ELX, ELY);
 
+  boolean through_center = ((ELX * TILEX + 14 - LX) * YS ==
+                           (ELY * TILEY + 14 - LY) * XS);
+
   // this is more precise: check if laser would go through the center
-  if ((ELX * TILEX + 14 - LX) * YS != (ELY * TILEY + 14 - LY) * XS)
+  if (!IS_DF_SLOPE(element) && !through_center)
   {
+    int skip_count = 0;
+
+    // prevent cutting through laser emitter with laser beam
+    if (IS_LASER(element))
+      return TRUE;
+
     // skip the whole element before continuing the scan
     do
     {
       LX += XS;
       LY += YS;
+
+      skip_count++;
     }
     while (ELX == LX/TILEX && ELY == LY/TILEY && LX > 0 && LY > 0);
 
-    if (LX/TILEX > ELX || LY/TILEY > ELY)
+    if ((LX/TILEX > ELX || LY/TILEY > ELY) && skip_count > 1)
     {
       /* skipping scan positions to the right and down skips one scan
         position too much, because this is only the top left scan position
         of totally four scan positions (plus one to the right, one to the
         bottom and one to the bottom right) */
+      /* ... but only roll back scan position if more than one step done */
 
       LX -= XS;
       LY -= YS;
@@ -1399,10 +1853,28 @@ boolean HitElement(int element, int hit_mask)
     return TRUE;
   }
 
-  if (!IS_BEAMER(element) &&
-      !IS_FIBRE_OPTIC(element) &&
-      !IS_GRID_WOOD(element) &&
-      element != EL_FUEL_EMPTY)
+  if (IS_DF_SLOPE(element) && !through_center)
+  {
+    int correction = 2;
+
+    if (hit_mask == HIT_MASK_ALL)
+    {
+      // laser already inside slope -- go back half step
+      LX -= XS / 2;
+      LY -= YS / 2;
+
+      correction = 1;
+    }
+
+    AddLaserEdge(LX, LY);
+
+    LX -= (ABS(XS) < ABS(YS) ? correction * SIGN(XS) : 0);
+    LY -= (ABS(YS) < ABS(XS) ? correction * SIGN(YS) : 0);
+  }
+  else if (!IS_BEAMER(element) &&
+          !IS_FIBRE_OPTIC(element) &&
+          !IS_GRID_WOOD(element) &&
+          element != EL_FUEL_EMPTY)
   {
 #if 0
     if ((ELX * TILEX + 14 - LX) * YS == (ELY * TILEY + 14 - LY) * XS)
@@ -1423,6 +1895,8 @@ boolean HitElement(int element, int hit_mask)
       IS_POLAR_CROSS(element) ||
       IS_DF_MIRROR(element) ||
       IS_DF_MIRROR_AUTO(element) ||
+      IS_DF_MIRROR_FIXED(element) ||
+      IS_DF_SLOPE(element) ||
       element == EL_PRISM ||
       element == EL_REFRACTOR)
   {
@@ -1441,7 +1915,9 @@ boolean HitElement(int element, int hit_mask)
     if (IS_MIRROR(element) ||
        IS_MIRROR_FIXED(element) ||
        IS_DF_MIRROR(element) ||
-       IS_DF_MIRROR_AUTO(element))
+       IS_DF_MIRROR_AUTO(element) ||
+       IS_DF_MIRROR_FIXED(element) ||
+       IS_DF_SLOPE(element))
       laser.current_angle = get_mirrored_angle(laser.current_angle,
                                               get_element_angle(element));
 
@@ -1451,22 +1927,36 @@ boolean HitElement(int element, int hit_mask)
     XS = 2 * Step[laser.current_angle].x;
     YS = 2 * Step[laser.current_angle].y;
 
-    if (!IS_22_5_ANGLE(laser.current_angle))   // 90° or 45° angle
-      step_size = 8;
-    else
-      step_size = 4;
+    if (through_center)
+    {
+      // start from center position for all game elements but slope
+      if (!IS_22_5_ANGLE(laser.current_angle)) // 90° or 45° angle
+       step_size = 8;
+      else
+       step_size = 4;
 
-    LX += step_size * XS;
-    LY += step_size * YS;
+      LX += step_size * XS;
+      LY += step_size * YS;
+    }
+    else
+    {
+      // advance laser position until reaching the next tile (slopes)
+      while (LX / TILEX == ELX && (LX + 2) / TILEX == ELX &&
+            LY / TILEY == ELY && (LY + 2) / TILEY == ELY)
+      {
+       LX += XS;
+       LY += YS;
+      }
+    }
 
-#if 0
     // draw sparkles on mirror
-    if ((IS_MIRROR(element) || IS_MIRROR_FIXED(element)) &&
+    if ((IS_MIRROR(element) ||
+        IS_MIRROR_FIXED(element) ||
+        element == EL_PRISM) &&
        current_angle != laser.current_angle)
     {
-      MoveSprite(vp, &Pfeil[2], 4 + 16 * ELX, 5 + 16 * ELY + 1);
+      MovDelay[ELX][ELY] = 11;         // start animation
     }
-#endif
 
     if ((!IS_POLAR(element) && !IS_POLAR_CROSS(element)) &&
        current_angle != laser.current_angle)
@@ -1476,6 +1966,68 @@ boolean HitElement(int element, int hit_mask)
       (get_opposite_angle(laser.current_angle) ==
        laser.damage[laser.num_damages - 1].angle ? TRUE : FALSE);
 
+    if (IS_DF_SLOPE(element))
+    {
+      // handle special cases for slope element
+
+      if (IS_45_ANGLE(laser.current_angle))
+      {
+       int elx, ely;
+
+       elx = getLevelFromLaserX(LX + XS);
+       ely = getLevelFromLaserY(LY + YS);
+
+       if (IN_LEV_FIELD(elx, ely))
+       {
+         int element_next = Tile[elx][ely];
+
+         // check if slope is followed by slope with opposite orientation
+         if (IS_DF_SLOPE(element_next) && ABS(element - element_next) == 2)
+           laser.overloaded = TRUE;
+       }
+
+       int nr = element - EL_DF_SLOPE_START;
+       int dx = (nr == 0 ? (XS > 0 ? TILEX - 1 : -1) :
+                 nr == 1 ? (XS > 0 ? TILEX     :  0) :
+                 nr == 2 ? (XS > 0 ? TILEX     :  0) :
+                 nr == 3 ? (XS > 0 ? TILEX - 1 : -1) : 0);
+       int dy = (nr == 0 ? (YS > 0 ? TILEY - 1 : -1) :
+                 nr == 1 ? (YS > 0 ? TILEY - 1 : -1) :
+                 nr == 2 ? (YS > 0 ? TILEY     :  0) :
+                 nr == 3 ? (YS > 0 ? TILEY     :  0) : 0);
+
+       int px = ELX * TILEX + dx;
+       int py = ELY * TILEY + dy;
+
+       dx = px % TILEX;
+       dy = py % TILEY;
+
+       elx = getLevelFromLaserX(px);
+       ely = getLevelFromLaserY(py);
+
+       if (IN_LEV_FIELD(elx, ely))
+       {
+         int element_side = Tile[elx][ely];
+
+         // check if end of slope is blocked by other element
+         if (IS_WALL(element_side) || IS_WALL_CHANGING(element_side))
+         {
+           int pos = dy / MINI_TILEY * 2 + dx / MINI_TILEX;
+
+           if (element & (1 << pos))
+             laser.overloaded = TRUE;
+         }
+         else
+         {
+           int pos = getMaskFromElement(element_side);
+
+           if (getPixelFromMask(pos, dx, dy))
+             laser.overloaded = TRUE;
+         }
+       }
+      }
+    }
+
     return (laser.overloaded ? TRUE : FALSE);
   }
 
@@ -1486,10 +2038,20 @@ boolean HitElement(int element, int hit_mask)
     return TRUE;
   }
 
-  if (element == EL_BOMB || element == EL_MINE)
+  if (element == EL_BOMB || element == EL_MINE || element == EL_GRAY_BALL)
   {
     PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
 
+    Tile[ELX][ELY] = (element == EL_BOMB ? EL_BOMB_ACTIVE :
+                     element == EL_MINE ? EL_MINE_ACTIVE :
+                     EL_GRAY_BALL_ACTIVE);
+
+    GfxFrame[ELX][ELY] = 0;            // restart animation
+
+    laser.dest_element_last = Tile[ELX][ELY];
+    laser.dest_element_last_x = ELX;
+    laser.dest_element_last_y = ELY;
+
     if (element == EL_MINE)
       laser.overloaded = TRUE;
   }
@@ -1499,9 +2061,11 @@ boolean HitElement(int element, int hit_mask)
       element == EL_KEY ||
       element == EL_LIGHTBALL ||
       element == EL_PACMAN ||
-      IS_PACMAN(element))
+      IS_PACMAN(element) ||
+      IS_ENVELOPE(element))
   {
-    if (!IS_PACMAN(element))
+    if (!IS_PACMAN(element) &&
+       !IS_ENVELOPE(element))
       Bang_MM(ELX, ELY);
 
     if (element == EL_PACMAN)
@@ -1529,6 +2093,10 @@ boolean HitElement(int element, int hit_mask)
     {
       DeletePacMan(ELX, ELY);
     }
+    else if (IS_ENVELOPE(element))
+    {
+      Tile[ELX][ELY] = EL_ENVELOPE_1_OPENING + ENVELOPE_NR(Tile[ELX][ELY]);
+    }
 
     RaiseScoreElement_MM(element);
 
@@ -1638,7 +2206,7 @@ boolean HitElement(int element, int hit_mask)
   return TRUE;
 }
 
-boolean HitOnlyAnEdge(int element, int hit_mask)
+static boolean HitOnlyAnEdge(int hit_mask)
 {
   // check if the laser hit only the edge of an element and, if so, go on
 
@@ -1695,9 +2263,9 @@ boolean HitOnlyAnEdge(int element, int hit_mask)
   return FALSE;
 }
 
-boolean HitPolarizer(int element, int hit_mask)
+static boolean HitPolarizer(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (IS_DF_GRID(element))
@@ -1762,17 +2330,23 @@ boolean HitPolarizer(int element, int hit_mask)
   }
   else if (IS_GRID_STEEL(element))
   {
+    // may be required if graphics for steel grid redefined
+    AddDamagedField(ELX, ELY);
+
     return HitReflectingWalls(element, hit_mask);
   }
   else // IS_GRID_WOOD
   {
+    // may be required if graphics for wooden grid redefined
+    AddDamagedField(ELX, ELY);
+
     return HitAbsorbingWalls(element, hit_mask);
   }
 
   return TRUE;
 }
 
-boolean HitBlock(int element, int hit_mask)
+static boolean HitBlock(int element, int hit_mask)
 {
   boolean check = FALSE;
 
@@ -1815,11 +2389,9 @@ boolean HitBlock(int element, int hit_mask)
   if (element == EL_GATE_STONE || element == EL_GATE_WOOD)
   {
     int xs = XS / 2, ys = YS / 2;
-    int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT;
-    int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT;
 
-    if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 ||
-       (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2)
+    if ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1 ||
+       (hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2)
     {
       laser.overloaded = (element == EL_GATE_STONE);
 
@@ -1858,11 +2430,9 @@ boolean HitBlock(int element, int hit_mask)
   if (element == EL_BLOCK_STONE || element == EL_BLOCK_WOOD)
   {
     int xs = XS / 2, ys = YS / 2;
-    int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT;
-    int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT;
 
-    if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 ||
-       (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2)
+    if ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1 ||
+       (hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2)
     {
       laser.overloaded = (element == EL_BLOCK_STONE);
 
@@ -1893,9 +2463,9 @@ boolean HitBlock(int element, int hit_mask)
   return TRUE;
 }
 
-boolean HitLaserSource(int element, int hit_mask)
+static boolean HitLaserSource(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
@@ -1905,9 +2475,9 @@ boolean HitLaserSource(int element, int hit_mask)
   return TRUE;
 }
 
-boolean HitLaserDestination(int element, int hit_mask)
+static boolean HitLaserDestination(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (element != EL_EXIT_OPEN &&
@@ -1951,7 +2521,7 @@ boolean HitLaserDestination(int element, int hit_mask)
   return TRUE;
 }
 
-boolean HitReflectingWalls(int element, int hit_mask)
+static boolean HitReflectingWalls(int element, int hit_mask)
 {
   // check if laser hits side of a wall with an angle that is not 90°
   if (!IS_90_ANGLE(laser.current_angle) && (hit_mask == HIT_MASK_TOP ||
@@ -2143,7 +2713,7 @@ boolean HitReflectingWalls(int element, int hit_mask)
     }
   }
 
-  if (!HitOnlyAnEdge(element, hit_mask))
+  if (!HitOnlyAnEdge(hit_mask))
   {
     laser.overloaded = TRUE;
 
@@ -2153,9 +2723,9 @@ boolean HitReflectingWalls(int element, int hit_mask)
   return FALSE;
 }
 
-boolean HitAbsorbingWalls(int element, int hit_mask)
+static boolean HitAbsorbingWalls(int element, int hit_mask)
 {
-  if (HitOnlyAnEdge(element, hit_mask))
+  if (HitOnlyAnEdge(hit_mask))
     return FALSE;
 
   if (ABS(XS) == 4 &&
@@ -2192,10 +2762,18 @@ boolean HitAbsorbingWalls(int element, int hit_mask)
 
   if (IS_WALL_ICE(element))
   {
+    int lx = LX + XS;
+    int ly = LY + YS;
     int mask;
 
-    mask = (LX + XS) / MINI_TILEX - ELX * 2 + 1;    // Quadrant (horizontal)
-    mask <<= (((LY + YS) / MINI_TILEY - ELY * 2) > 0) * 2;  // || (vertical)
+    // check if laser hit adjacent edges of two diagonal tiles
+    if (ELX != lx / TILEX)
+      lx = LX - XS;
+    if (ELY != ly / TILEY)
+      ly = LY - YS;
+
+    mask =     lx / MINI_TILEX - ELX * 2 + 1;    // Quadrant (horizontal)
+    mask <<= ((ly / MINI_TILEY - ELY * 2) > 0 ? 2 : 0);  // || (vertical)
 
     // check if laser hits wall with an angle of 90°
     if (IS_90_ANGLE(laser.current_angle))
@@ -2247,7 +2825,7 @@ boolean HitAbsorbingWalls(int element, int hit_mask)
     if (IS_90_ANGLE(laser.current_angle))
       mask += mask * (2 + IS_HORIZ_ANGLE(laser.current_angle) * 2);
 
-    laser.dest_element = element2 | EL_WALL_AMOEBA;
+    laser.dest_element = element2 | EL_WALL_AMOEBA_BASE;
 
     laser.wall_mask = mask;
   }
@@ -2280,12 +2858,25 @@ static void OpenExit(int x, int y)
   }
 }
 
-static void OpenSurpriseBall(int x, int y)
+static void OpenGrayBall(int x, int y)
 {
   int delay = 2;
 
   if (!MovDelay[x][y])         // next animation frame
+  {
+    if (IS_WALL(Store[x][y]))
+    {
+      DrawWalls_MM(x, y, Store[x][y]);
+
+      // copy wall tile to spare bitmap for "melting" animation
+      BlitBitmap(drawto_mm, bitmap_db_field, cSX + x * TILEX, cSY + y * TILEY,
+                TILEX, TILEY, x * TILEX, y * TILEY);
+
+      DrawElement_MM(x, y, EL_GRAY_BALL);
+    }
+
     MovDelay[x][y] = 50 * delay;
+  }
 
   if (MovDelay[x][y])          // wait some time before next frame
   {
@@ -2294,25 +2885,77 @@ static void OpenSurpriseBall(int x, int y)
     if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y))
     {
       Bitmap *bitmap;
-      int graphic = el2gfx(Store[x][y]);
       int gx, gy;
       int dx = RND(26), dy = RND(26);
 
-      getGraphicSource(graphic, 0, &bitmap, &gx, &gy);
+      if (IS_WALL(Store[x][y]))
+      {
+       // copy wall tile from spare bitmap for "melting" animation
+       bitmap = bitmap_db_field;
+       gx = x * TILEX;
+       gy = y * TILEY;
+      }
+      else
+      {
+       int graphic = el2gfx(Store[x][y]);
 
-      BlitBitmap(bitmap, drawto, gx + dx, gy + dy, 6, 6,
+       getGraphicSource(graphic, 0, &bitmap, &gx, &gy);
+      }
+
+      BlitBitmap(bitmap, drawto_mm, gx + dx, gy + dy, 6, 6,
                 cSX + x * TILEX + dx, cSY + y * TILEY + dy);
 
+      laser.redraw = TRUE;
+
       MarkTileDirty(x, y);
     }
 
     if (!MovDelay[x][y])
     {
       Tile[x][y] = Store[x][y];
-      Store[x][y] = 0;
+      Store[x][y] = Store2[x][y] = 0;
+      MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+
+      InitField(x, y, FALSE);
+      DrawField_MM(x, y);
+
+      ScanLaser_FromLastMirror();
+    }
+  }
+}
+
+static void OpenEnvelope(int x, int y)
+{
+  int num_frames = 8;          // seven frames plus final empty space
+
+  if (!MovDelay[x][y])         // next animation frame
+    MovDelay[x][y] = num_frames;
+
+  if (MovDelay[x][y])          // wait some time before next frame
+  {
+    int nr = ENVELOPE_OPENING_NR(Tile[x][y]);
+
+    MovDelay[x][y]--;
+
+    if (MovDelay[x][y] > 0 && IN_SCR_FIELD(x, y))
+    {
+      int graphic = el_act2gfx(EL_ENVELOPE_1 + nr, MM_ACTION_COLLECTING);
+      int frame = num_frames - MovDelay[x][y] - 1;
+
+      DrawGraphicAnimation_MM(x, y, graphic, frame);
+
+      laser.redraw = TRUE;
+    }
+
+    if (MovDelay[x][y] == 0)
+    {
+      Tile[x][y] = EL_EMPTY;
+
       DrawField_MM(x, y);
 
       ScanLaser();
+
+      ShowEnvelope(nr);
     }
   }
 }
@@ -2329,33 +2972,22 @@ static void MeltIce(int x, int y)
   {
     int phase;
     int wall_mask = Store2[x][y];
-    int real_element = Tile[x][y] - EL_WALL_CHANGING + EL_WALL_ICE;
+    int real_element = Tile[x][y] - EL_WALL_CHANGING_BASE + EL_WALL_ICE_BASE;
 
     MovDelay[x][y]--;
     phase = frames - MovDelay[x][y] / delay - 1;
 
     if (!MovDelay[x][y])
     {
-      int i;
-
       Tile[x][y] = real_element & (wall_mask ^ 0xFF);
       Store[x][y] = Store2[x][y] = 0;
 
       DrawWalls_MM(x, y, Tile[x][y]);
 
-      if (Tile[x][y] == EL_WALL_ICE)
+      if (Tile[x][y] == EL_WALL_ICE_BASE)
        Tile[x][y] = EL_EMPTY;
 
-      for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--)
-       if (laser.damage[i].is_mirror)
-         break;
-
-      if (i > 0)
-       DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
-      else
-       DrawLaser(0, DL_LASER_DISABLED);
-
-      ScanLaser();
+      ScanLaser_FromLastMirror();
     }
     else if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y))
     {
@@ -2378,7 +3010,7 @@ static void GrowAmoeba(int x, int y)
   {
     int phase;
     int wall_mask = Store2[x][y];
-    int real_element = Tile[x][y] - EL_WALL_CHANGING + EL_WALL_AMOEBA;
+    int real_element = Tile[x][y] - EL_WALL_CHANGING_BASE + EL_WALL_AMOEBA_BASE;
 
     MovDelay[x][y]--;
     phase = MovDelay[x][y] / delay;
@@ -2398,17 +3030,58 @@ static void GrowAmoeba(int x, int y)
   }
 }
 
+static void DrawFieldAnimated_MM(int x, int y)
+{
+  DrawField_MM(x, y);
+
+  laser.redraw = TRUE;
+}
+
+static void DrawFieldAnimatedIfNeeded_MM(int x, int y)
+{
+  int element = Tile[x][y];
+  int graphic = el2gfx(element);
+
+  if (!getGraphicInfo_NewFrame(x, y, graphic))
+    return;
+
+  DrawField_MM(x, y);
+
+  laser.redraw = TRUE;
+}
+
+static void DrawFieldTwinkle(int x, int y)
+{
+  if (MovDelay[x][y] != 0)     // wait some time before next frame
+  {
+    MovDelay[x][y]--;
+
+    DrawField_MM(x, y);
+
+    if (MovDelay[x][y] != 0)
+    {
+      int graphic = IMG_TWINKLE_WHITE;
+      int frame = getGraphicAnimationFrame(graphic, 10 - MovDelay[x][y]);
+
+      DrawGraphicThruMask_MM(SCREENX(x), SCREENY(y), graphic, frame);
+    }
+
+    laser.redraw = TRUE;
+  }
+}
+
 static void Explode_MM(int x, int y, int phase, int mode)
 {
   int num_phase = 9, delay = 2;
   int last_phase = num_phase * delay;
   int half_phase = (num_phase / 2) * delay;
+  int center_element;
 
   laser.redraw = TRUE;
 
   if (phase == EX_PHASE_START)         // initialize 'Store[][]' field
   {
-    int center_element = Tile[x][y];
+    center_element = Tile[x][y];
 
     if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
     {
@@ -2419,22 +3092,32 @@ static void Explode_MM(int x, int y, int phase, int mode)
       Tile[x][y] = center_element;
     }
 
-    if (center_element == EL_BOMB || IS_MCDUFFIN(center_element))
-      Store[x][y] = center_element;
-    else
+    if (center_element != EL_GRAY_BALL_ACTIVE)
       Store[x][y] = EL_EMPTY;
+    Store2[x][y] = center_element;
 
-    Store2[x][y] = mode;
     Tile[x][y] = EL_EXPLODING_OPAQUE;
+
+    GfxElement[x][y] = (center_element == EL_BOMB_ACTIVE ? EL_BOMB :
+                       center_element == EL_GRAY_BALL_ACTIVE ? EL_GRAY_BALL :
+                       IS_MCDUFFIN(center_element) ? EL_MCDUFFIN :
+                       center_element);
+
     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
-    Frame[x][y] = 1;
+
+    ExplodePhase[x][y] = 1;
 
     return;
   }
 
-  Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
+  if (phase == 1)
+    GfxFrame[x][y] = 0;                // restart explosion animation
+
+  ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
+
+  center_element = Store2[x][y];
 
-  if (phase == half_phase)
+  if (phase == half_phase && Store[x][y] == EL_EMPTY)
   {
     Tile[x][y] = EL_EXPLODING_TRANSP;
 
@@ -2444,75 +3127,37 @@ static void Explode_MM(int x, int y, int phase, int mode)
 
   if (phase == last_phase)
   {
-    if (Store[x][y] == EL_BOMB)
+    if (center_element == EL_BOMB_ACTIVE)
     {
       DrawLaser(0, DL_LASER_DISABLED);
       InitLaser();
 
       Bang_MM(laser.start_edge.x, laser.start_edge.y);
-      Store[x][y] = EL_EMPTY;
-
-      game_mm.game_over = TRUE;
-      game_mm.game_over_cause = GAME_OVER_BOMB;
-
-      SetTileCursorActive(FALSE);
 
       laser.overloaded = FALSE;
     }
-    else if (IS_MCDUFFIN(Store[x][y]))
+    else if (IS_MCDUFFIN(center_element) || IS_LASER(center_element))
     {
-      Store[x][y] = EL_EMPTY;
-
-      game.restart_game_message = "Bomb killed Mc Duffin! Play it again?";
+      GameOver_MM(GAME_OVER_BOMB);
     }
 
     Tile[x][y] = Store[x][y];
+
     Store[x][y] = Store2[x][y] = 0;
     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
 
     InitField(x, y, FALSE);
     DrawField_MM(x, y);
+
+    if (center_element == EL_GRAY_BALL_ACTIVE)
+      ScanLaser_FromLastMirror();
   }
   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
-    int graphic = IMG_MM_DEFAULT_EXPLODING;
-    int graphic_phase = (phase / delay - 1);
-    Bitmap *bitmap;
-    int src_x, src_y;
-
-    if (Store2[x][y] == EX_KETTLE)
-    {
-      if (graphic_phase < 3)
-      {
-       graphic = IMG_MM_KETTLE_EXPLODING;
-      }
-      else if (graphic_phase < 5)
-      {
-       graphic_phase += 3;
-      }
-      else
-      {
-       graphic = IMG_EMPTY;
-       graphic_phase = 0;
-      }
-    }
-    else if (Store2[x][y] == EX_SHORT)
-    {
-      if (graphic_phase < 4)
-      {
-       graphic_phase += 4;
-      }
-      else
-      {
-       graphic = IMG_EMPTY;
-       graphic_phase = 0;
-      }
-    }
+    int graphic = el_act2gfx(GfxElement[x][y], MM_ACTION_EXPLODING);
+    int frame = getGraphicAnimationFrameXY(graphic, x, y);
 
-    getGraphicSource(graphic, graphic_phase, &bitmap, &src_x, &src_y);
-
-    BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY,
-              cFX + x * TILEX, cFY + y * TILEY);
+    DrawGraphicAnimation_MM(x, y, graphic, frame);
 
     MarkTileDirty(x, y);
   }
@@ -2521,67 +3166,48 @@ static void Explode_MM(int x, int y, int phase, int mode)
 static void Bang_MM(int x, int y)
 {
   int element = Tile[x][y];
-  int mode = EX_NORMAL;
-
-#if 0
-  DrawLaser(0, DL_LASER_ENABLED);
-#endif
-
-  switch (element)
-  {
-    case EL_KETTLE:
-      mode = EX_KETTLE;
-      break;
-
-    case EL_GATE_STONE:
-    case EL_GATE_WOOD:
-      mode = EX_SHORT;
-      break;
-
-    default:
-      mode = EX_NORMAL;
-      break;
-  }
 
   if (IS_PACMAN(element))
     PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
-  else if (element == EL_BOMB || IS_MCDUFFIN(element))
+  else if (element == EL_BOMB_ACTIVE || IS_MCDUFFIN(element))
     PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
   else if (element == EL_KEY)
     PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
   else
     PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
 
-  Explode_MM(x, y, EX_PHASE_START, mode);
+  Explode_MM(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
 }
 
-void TurnRound(int x, int y)
+static void TurnRound(int x, int y)
 {
   static struct
   {
     int x, y;
   } move_xy[] =
   {
-    { 0, 0 },
-    {-1, 0 },
-    {+1, 0 },
-    { 0, 0 },
-    { 0, -1 },
-    { 0, 0 }, { 0, 0 }, { 0, 0 },
-    { 0, +1 }
+    {  0,  0 },
+    { -1,  0 },
+    { +1,  0 },
+    {  0,  0 },
+    {  0, -1 },
+    {  0,  0 }, { 0, 0 }, { 0, 0 },
+    {  0, +1 }
   };
   static struct
   {
     int left, right, back;
   } turn[] =
   {
-    { 0,       0,              0 },
+    { 0,       0,              0        },
     { MV_DOWN, MV_UP,          MV_RIGHT },
-    { MV_UP,   MV_DOWN,        MV_LEFT },
-    { 0,       0,              0 },
-    { MV_LEFT, MV_RIGHT,       MV_DOWN },
-    { 0,0,0 }, { 0,0,0 },      { 0,0,0 },
-    { MV_RIGHT,        MV_LEFT,        MV_UP }
+    { MV_UP,   MV_DOWN,        MV_LEFT  },
+    { 0,       0,              0        },
+    { MV_LEFT, MV_RIGHT,       MV_DOWN  },
+    { 0,       0,              0        },
+    { 0,       0,              0        },
+    { 0,       0,              0        },
+    { MV_RIGHT,        MV_LEFT,        MV_UP    }
   };
 
   int element = Tile[x][y];
@@ -2629,7 +3255,7 @@ static void StartMoving_MM(int x, int y)
 
     // now make next step
 
-    Moving2Blocked_MM(x, y, &newx, &newy);     // get next screen position
+    Moving2Blocked(x, y, &newx, &newy);        // get next screen position
 
     if (element == EL_PACMAN &&
        IN_LEV_FIELD(newx, newy) && IS_EATABLE4PACMAN(Tile[newx][newy]) &&
@@ -2663,7 +3289,7 @@ static void ContinueMoving_MM(int x, int y)
   int direction = MovDir[x][y];
   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
   int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
-  int horiz_move = (dx!=0);
+  int horiz_move = (dx != 0);
   int newx = x + dx, newy = y + dy;
   int step = (horiz_move ? dx : dy) * TILEX / 8;
 
@@ -2709,8 +3335,7 @@ static void ContinueMoving_MM(int x, int y)
 
 boolean ClickElement(int x, int y, int button)
 {
-  static unsigned int click_delay = 0;
-  static int click_delay_value = CLICK_DELAY;
+  static DelayCounter click_delay = { CLICK_DELAY };
   static boolean new_button = TRUE;
   boolean element_clicked = FALSE;
   int element;
@@ -2718,8 +3343,8 @@ boolean ClickElement(int x, int y, int button)
   if (button == -1)
   {
     // initialize static variables
-    click_delay = 0;
-    click_delay_value = CLICK_DELAY;
+    click_delay.count = 0;
+    click_delay.value = CLICK_DELAY;
     new_button = TRUE;
 
     return FALSE;
@@ -2732,7 +3357,7 @@ boolean ClickElement(int x, int y, int button)
   if (button == MB_RELEASED)
   {
     new_button = TRUE;
-    click_delay_value = CLICK_DELAY;
+    click_delay.value = CLICK_DELAY;
 
     // release eventually hold auto-rotating mirror
     RotateMirror(x, y, MB_RELEASED);
@@ -2740,7 +3365,7 @@ boolean ClickElement(int x, int y, int button)
     return FALSE;
   }
 
-  if (!FrameReached(&click_delay, click_delay_value) && !new_button)
+  if (!FrameReached(&click_delay) && !new_button)
     return FALSE;
 
   if (button == MB_MIDDLEBUTTON)       // middle button has no function
@@ -2767,29 +3392,25 @@ boolean ClickElement(int x, int y, int button)
   }
   else if (IS_MCDUFFIN(element))
   {
-    if (!laser.fuse_off)
-    {
-      DrawLaser(0, DL_LASER_DISABLED);
+    boolean has_laser = (x == laser.start_edge.x && y == laser.start_edge.y);
 
-      /*
-      BackToFront();
-      */
-    }
+    if (has_laser && !laser.fuse_off)
+      DrawLaser(0, DL_LASER_DISABLED);
 
     element = get_rotated_element(element, BUTTON_ROTATION(button));
-    laser.start_angle = get_element_angle(element);
-
-    InitLaser();
 
     Tile[x][y] = element;
     DrawField_MM(x, y);
 
-    /*
-    BackToFront();
-    */
+    if (has_laser)
+    {
+      laser.start_angle = get_element_angle(element);
 
-    if (!laser.fuse_off)
-      ScanLaser();
+      InitLaser();
+
+      if (!laser.fuse_off)
+       ScanLaser();
+    }
 
     element_clicked = TRUE;
   }
@@ -2826,14 +3447,20 @@ boolean ClickElement(int x, int y, int button)
 
     element_clicked = TRUE;
   }
+  else if (IS_ENVELOPE(element))
+  {
+    Tile[x][y] = EL_ENVELOPE_1_OPENING + ENVELOPE_NR(element);
 
-  click_delay_value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
+    element_clicked = TRUE;
+  }
+
+  click_delay.value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
   new_button = FALSE;
 
   return element_clicked;
 }
 
-void RotateMirror(int x, int y, int button)
+static void RotateMirror(int x, int y, int button)
 {
   if (button == MB_RELEASED)
   {
@@ -2908,8 +3535,6 @@ void RotateMirror(int x, int y, int button)
         IS_POLAR(Tile[x][y]) ||
         IS_POLAR_CROSS(Tile[x][y])) && x == ELX && y == ELY)
     {
-      check = 0;
-
       if (IS_BEAMER(Tile[x][y]))
       {
 #if 0
@@ -2917,10 +3542,13 @@ void RotateMirror(int x, int y, int button)
              LX, LY, laser.beamer_edge, laser.beamer[1].num);
 #endif
 
-       laser.num_edges--;
+       if (check == 1)
+         laser.num_edges--;
       }
 
       ScanLaser();
+
+      check = 0;
     }
 
     if (check == 2)
@@ -2932,7 +3560,7 @@ static void AutoRotateMirrors(void)
 {
   int x, y;
 
-  if (!FrameReached(&rotate_delay, AUTO_ROTATE_DELAY))
+  if (!FrameReached(&rotate_delay))
     return;
 
   for (x = 0; x < lev_fieldx; x++)
@@ -2949,12 +3577,16 @@ static void AutoRotateMirrors(void)
          IS_GRID_WOOD_AUTO(element) ||
          IS_GRID_STEEL_AUTO(element) ||
          element == EL_REFRACTOR)
+      {
        RotateMirror(x, y, MB_RIGHTBUTTON);
+
+       laser.redraw = TRUE;
+      }
     }
   }
 }
 
-boolean ObjHit(int obx, int oby, int bits)
+static boolean ObjHit(int obx, int oby, int bits)
 {
   int i;
 
@@ -2987,7 +3619,7 @@ boolean ObjHit(int obx, int oby, int bits)
   return FALSE;
 }
 
-void DeletePacMan(int px, int py)
+static void DeletePacMan(int px, int py)
 {
   int i, j;
 
@@ -3013,51 +3645,7 @@ void DeletePacMan(int px, int py)
   }
 }
 
-void ColorCycling(void)
-{
-  static int CC, Cc = 0;
-
-  static int color, old = 0xF00, new = 0x010, mult = 1;
-  static unsigned short red, green, blue;
-
-  if (color_status == STATIC_COLORS)
-    return;
-
-  CC = FrameCounter;
-
-  if (CC < Cc || CC > Cc + 2)
-  {
-    Cc = CC;
-
-    color = old + new * mult;
-    if (mult > 0)
-      mult++;
-    else
-      mult--;
-
-    if (ABS(mult) == 16)
-    {
-      mult =- mult / 16;
-      old = color;
-      new = new << 4;
-
-      if (new > 0x100)
-       new = 0x001;
-    }
-
-    red   = 0x0e00 * ((color & 0xF00) >> 8);
-    green = 0x0e00 * ((color & 0x0F0) >> 4);
-    blue  = 0x0e00 * ((color & 0x00F));
-    SetRGB(pen_magicolor[0], red, green, blue);
-
-    red   = 0x1111 * ((color & 0xF00) >> 8);
-    green = 0x1111 * ((color & 0x0F0) >> 4);
-    blue  = 0x1111 * ((color & 0x00F));
-    SetRGB(pen_magicolor[1], red, green, blue);
-  }
-}
-
-static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
+static void GameActions_MM_Ext(void)
 {
   int element;
   int x, y, i;
@@ -3076,15 +3664,27 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     else if (IS_MOVING(x, y))
       ContinueMoving_MM(x, y);
     else if (IS_EXPLODING(element))
-      Explode_MM(x, y, Frame[x][y], EX_NORMAL);
+      Explode_MM(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
     else if (element == EL_EXIT_OPENING)
       OpenExit(x, y);
     else if (element == EL_GRAY_BALL_OPENING)
-      OpenSurpriseBall(x, y);
-    else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_ICE)
+      OpenGrayBall(x, y);
+    else if (IS_ENVELOPE_OPENING(element))
+      OpenEnvelope(x, y);
+    else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_ICE_BASE)
       MeltIce(x, y);
-    else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA)
+    else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA_BASE)
       GrowAmoeba(x, y);
+    else if (IS_MIRROR(element) ||
+            IS_MIRROR_FIXED(element) ||
+            element == EL_PRISM)
+      DrawFieldTwinkle(x, y);
+    else if (element == EL_GRAY_BALL_ACTIVE ||
+            element == EL_BOMB_ACTIVE ||
+            element == EL_MINE_ACTIVE)
+      DrawFieldAnimated_MM(x, y);
+    else if (!IS_BLOCKED(x, y))
+      DrawFieldAnimatedIfNeeded_MM(x, y);
   }
 
   AutoRotateMirrors();
@@ -3100,7 +3700,7 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
   CT = FrameCounter;
 
-  if (game_mm.num_pacman && FrameReached(&pacman_delay, PACMAN_MOVE_DELAY))
+  if (game_mm.num_pacman && FrameReached(&pacman_delay))
   {
     MovePacMen();
 
@@ -3111,48 +3711,25 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     }
   }
 
-  if (FrameReached(&energy_delay, ENERGY_DELAY))
-  {
-    if (game_mm.energy_left > 0)
-    {
-      game_mm.energy_left--;
-
-      redraw_mask |= REDRAW_DOOR_1;
-    }
-    else if (setup.time_limit && !game_mm.game_over)
-    {
-      int i;
-
-      for (i = 15; i >= 0; i--)
-      {
-#if 0
-       SetRGB(pen_ray, 0x0000, 0x0000, i * color_scale);
-#endif
-       pen_ray = GetPixelFromRGB(window,
-                                 native_mm_level.laser_red   * 0x11 * i,
-                                 native_mm_level.laser_green * 0x11 * i,
-                                 native_mm_level.laser_blue  * 0x11 * i);
-
-       DrawLaser(0, DL_LASER_ENABLED);
-       BackToFront();
-       Delay_WithScreenUpdates(50);
-      }
+  // skip all following game actions if game is over
+  if (game_mm.game_over)
+    return;
 
-      StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
-#if 0
-      FadeMusic();
-#endif
+  if (game_mm.energy_left == 0 && !game.no_level_time_limit && game.time_limit)
+  {
+    FadeOutLaser();
 
-      DrawLaser(0, DL_LASER_DISABLED);
-      game_mm.game_over = TRUE;
-      game_mm.game_over_cause = GAME_OVER_NO_ENERGY;
+    GameOver_MM(GAME_OVER_NO_ENERGY);
 
-      SetTileCursorActive(FALSE);
+    return;
+  }
 
-      game.restart_game_message = "Out of magic energy! Play it again?";
+  if (FrameReached(&energy_delay))
+  {
+    if (game_mm.energy_left > 0)
+      game_mm.energy_left--;
 
-      return;
-    }
+    // when out of energy, wait another frame to play "out of time" sound
   }
 
   element = laser.dest_element;
@@ -3167,8 +3744,11 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
   if (!laser.overloaded && laser.overload_value == 0 &&
       element != EL_BOMB &&
+      element != EL_BOMB_ACTIVE &&
       element != EL_MINE &&
-      element != EL_BALL_GRAY &&
+      element != EL_MINE_ACTIVE &&
+      element != EL_GRAY_BALL &&
+      element != EL_GRAY_BALL_ACTIVE &&
       element != EL_BLOCK_STONE &&
       element != EL_BLOCK_WOOD &&
       element != EL_FUSE_ON &&
@@ -3177,9 +3757,11 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
       !IS_WALL_AMOEBA(element))
     return;
 
+  overload_delay.value = HEALTH_DELAY(laser.overloaded);
+
   if (((laser.overloaded && laser.overload_value < MAX_LASER_OVERLOAD) ||
        (!laser.overloaded && laser.overload_value > 0)) &&
-      FrameReached(&overload_delay, HEALTH_DELAY(laser.overloaded)))
+      FrameReached(&overload_delay))
   {
     if (laser.overloaded)
       laser.overload_value++;
@@ -3196,18 +3778,7 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
     if (laser.overload_value < MAX_LASER_OVERLOAD - 8)
     {
-      int color_up = 0xFF * laser.overload_value / MAX_LASER_OVERLOAD;
-      int color_down = 0xFF - color_up;
-
-#if 0
-      SetRGB(pen_ray, (laser.overload_value / 6) * color_scale, 0x0000,
-            (15 - (laser.overload_value / 6)) * color_scale);
-#endif
-      pen_ray =
-       GetPixelFromRGB(window,
-                       (native_mm_level.laser_red  ? 0xFF : color_up),
-                       (native_mm_level.laser_green ? color_down : 0x00),
-                       (native_mm_level.laser_blue  ? color_down : 0x00));
+      SetLaserColor(0xFF);
 
       DrawLaser(0, DL_LASER_ENABLED);
     }
@@ -3219,57 +3790,13 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     else
       PlaySound_MM(SND_MM_GAME_HEALTH_CHARGING);
 
-    if (laser.overloaded)
-    {
-#if 0
-      BlitBitmap(pix[PIX_DOOR], drawto,
-                DOOR_GFX_PAGEX4 + XX_OVERLOAD,
-                DOOR_GFX_PAGEY1 + YY_OVERLOAD + OVERLOAD_YSIZE
-                - laser.overload_value,
-                OVERLOAD_XSIZE, laser.overload_value,
-                DX_OVERLOAD, DY_OVERLOAD + OVERLOAD_YSIZE
-                - laser.overload_value);
-#endif
-      redraw_mask |= REDRAW_DOOR_1;
-    }
-    else
-    {
-#if 0
-      BlitBitmap(pix[PIX_DOOR], drawto,
-                DOOR_GFX_PAGEX5 + XX_OVERLOAD, DOOR_GFX_PAGEY1 + YY_OVERLOAD,
-                OVERLOAD_XSIZE, OVERLOAD_YSIZE - laser.overload_value,
-                DX_OVERLOAD, DY_OVERLOAD);
-#endif
-      redraw_mask |= REDRAW_DOOR_1;
-    }
-
     if (laser.overload_value == MAX_LASER_OVERLOAD)
     {
-      int i;
-
       UpdateAndDisplayGameControlValues();
 
-      for (i = 15; i >= 0; i--)
-      {
-#if 0
-       SetRGB(pen_ray, i * color_scale, 0x0000, 0x0000);
-#endif
-
-       pen_ray = GetPixelFromRGB(window, 0x11 * i, 0x00, 0x00);
-
-       DrawLaser(0, DL_LASER_ENABLED);
-       BackToFront();
-       Delay_WithScreenUpdates(50);
-      }
+      FadeOutLaser();
 
-      DrawLaser(0, DL_LASER_DISABLED);
-
-      game_mm.game_over = TRUE;
-      game_mm.game_over_cause = GAME_OVER_OVERLOADED;
-
-      SetTileCursorActive(FALSE);
-
-      game.restart_game_message = "Magic spell hit Mc Duffin! Play it again?";
+      GameOver_MM(GAME_OVER_OVERLOADED);
 
       return;
     }
@@ -3302,117 +3829,50 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
     DrawGraphic_MM(ELX, ELY, IMG_MM_FUSE);
   }
 
-  if (element == EL_BALL_GRAY && CT > native_mm_level.time_ball)
+  if (element == EL_GRAY_BALL && CT > native_mm_level.time_ball)
   {
-    static int new_elements[] =
+    if (!Store2[ELX][ELY])     // check if content element not yet determined
     {
-      EL_MIRROR_START,
-      EL_MIRROR_FIXED_START,
-      EL_POLAR_START,
-      EL_POLAR_CROSS_START,
-      EL_PACMAN_START,
-      EL_KETTLE,
-      EL_BOMB,
-      EL_PRISM
-    };
-    int num_new_elements = sizeof(new_elements) / sizeof(int);
-    int new_element = new_elements[RND(num_new_elements)];
-
-    Store[ELX][ELY] = new_element + RND(get_num_elements(new_element));
-    Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
-
-    // !!! CHECK AGAIN: Laser on Polarizer !!!
-    ScanLaser();
+      int last_anim_random_frame = gfx.anim_random_frame;
+      int element_pos;
 
-    return;
-
-#if 0
-    int graphic;
-
-    switch (RND(5))
-    {
-      case 0:
-        element = EL_MIRROR_START + RND(16);
-       break;
-      case 1:
-       {
-         int rnd = RND(3);
-
-         element = (rnd == 0 ? EL_KETTLE : rnd == 1 ? EL_BOMB : EL_PRISM);
-       }
-       break;
-      default:
-       {
-         int rnd = RND(3);
+      if (native_mm_level.ball_choice_mode == ANIM_RANDOM)
+       gfx.anim_random_frame = RND(native_mm_level.num_ball_contents);
 
-         element = (rnd == 0 ? EL_FUSE_ON :
-                    rnd >= 1 && rnd <= 4 ? EL_PACMAN_RIGHT + rnd - 1 :
-                    rnd >= 5 && rnd <= 20 ? EL_POLAR_START + rnd - 5 :
-                    rnd >= 21 && rnd <= 24 ? EL_POLAR_CROSS_START + rnd - 21 :
-                    EL_MIRROR_FIXED_START + rnd - 25);
-       }
-       break;
-    }
+      element_pos = getAnimationFrame(native_mm_level.num_ball_contents, 1,
+                                     native_mm_level.ball_choice_mode, 0,
+                                     game_mm.ball_choice_pos);
 
-    graphic = el2gfx(element);
+      if (native_mm_level.ball_choice_mode == ANIM_RANDOM)
+       gfx.anim_random_frame = last_anim_random_frame;
 
-    for (i = 0; i < 50; i++)
-    {
-      int x = RND(26);
-      int y = RND(26);
+      game_mm.ball_choice_pos++;
 
-#if 0
-      BlitBitmap(pix[PIX_BACK], drawto,
-                SX + (graphic % GFX_PER_LINE) * TILEX + x,
-                SY + (graphic / GFX_PER_LINE) * TILEY + y, 6, 6,
-                SX + ELX * TILEX + x,
-                SY + ELY * TILEY + y);
-#endif
-      MarkTileDirty(ELX, ELY);
-      BackToFront();
+      int new_element = native_mm_level.ball_content[element_pos];
+      int new_element_base = map_wall_to_base_element(new_element);
 
-      DrawLaser(0, DL_LASER_ENABLED);
+      if (IS_WALL(new_element_base))
+      {
+       // always use completely filled wall element
+       new_element = new_element_base | 0x000f;
+      }
+      else if (native_mm_level.rotate_ball_content &&
+              get_num_elements(new_element) > 1)
+      {
+       // randomly rotate newly created game element
+       new_element = get_rotated_element(new_element, RND(16));
+      }
 
-      Delay_WithScreenUpdates(50);
+      Store[ELX][ELY] = new_element;
+      Store2[ELX][ELY] = TRUE;
     }
 
-    Tile[ELX][ELY] = element;
-    DrawField_MM(ELX, ELY);
-
-#if 0
-    Debug("game:mm:GameActions_MM_Ext", "NEW ELEMENT: (%d, %d)", ELX, ELY);
-#endif
-
-    // above stuff: GRAY BALL -> PRISM !!!
-/*
-    LX = ELX * TILEX + 14;
-    LY = ELY * TILEY + 14;
-    if (laser.current_angle == (laser.current_angle >> 1) << 1)
-      OK = 8;
+    if (native_mm_level.explode_ball)
+      Bang_MM(ELX, ELY);
     else
-      OK = 4;
-    LX -= OK * XS;
-    LY -= OK * YS;
+      Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
 
-    laser.num_edges -= 2;
-    laser.num_damages--;
-*/
-
-#if 0
-    for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i>=0; i--)
-      if (laser.damage[i].is_mirror)
-       break;
-
-    if (i > 0)
-      DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
-    else
-      DrawLaser(0, DL_LASER_DISABLED);
-#else
-    DrawLaser(0, DL_LASER_DISABLED);
-#endif
-
-    ScanLaser();
-#endif
+    laser.dest_element = laser.dest_element_last = Tile[ELX][ELY];
 
     return;
   }
@@ -3421,57 +3881,18 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
   {
     PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_SHRINKING);
 
-    {
-      Tile[ELX][ELY] = Tile[ELX][ELY] - EL_WALL_ICE + EL_WALL_CHANGING;
-      Store[ELX][ELY] = EL_WALL_ICE;
-      Store2[ELX][ELY] = laser.wall_mask;
-
-      laser.dest_element = Tile[ELX][ELY];
-
-      return;
-    }
-
-    for (i = 0; i < 5; i++)
-    {
-      int phase = i + 1;
-
-      if (i == 4)
-      {
-       Tile[ELX][ELY] &= (laser.wall_mask ^ 0xFF);
-       phase = 0;
-      }
-
-      DrawWallsAnimation_MM(ELX, ELY, Tile[ELX][ELY], phase, laser.wall_mask);
-      BackToFront();
-      Delay_WithScreenUpdates(100);
-    }
-
-    if (Tile[ELX][ELY] == EL_WALL_ICE)
-      Tile[ELX][ELY] = EL_EMPTY;
+    Tile[ELX][ELY] = Tile[ELX][ELY] - EL_WALL_ICE_BASE + EL_WALL_CHANGING_BASE;
+    Store[ELX][ELY] = EL_WALL_ICE_BASE;
+    Store2[ELX][ELY] = laser.wall_mask;
 
-/*
-    laser.num_edges--;
-    LX = laser.edge[laser.num_edges].x - cSX2;
-    LY = laser.edge[laser.num_edges].y - cSY2;
-*/
-
-    for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--)
-      if (laser.damage[i].is_mirror)
-       break;
-
-    if (i > 0)
-      DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
-    else
-      DrawLaser(0, DL_LASER_DISABLED);
-
-    ScanLaser();
+    laser.dest_element = Tile[ELX][ELY];
 
     return;
   }
 
   if (IS_WALL_AMOEBA(element) && CT > 60)
   {
-    int k1, k2, k3, dx, dy, de, dm;
+    int k1, k2, k3;
     int element2 = Tile[ELX][ELY];
 
     if (element2 != EL_EMPTY && !IS_WALL_AMOEBA(element))
@@ -3542,44 +3963,17 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
     Tile[ELX][ELY] = element | laser.wall_mask;
 
-    dx = ELX;
-    dy = ELY;
-    de = Tile[ELX][ELY];
-    dm = laser.wall_mask;
+    int x = ELX, y = ELY;
+    int wall_mask = laser.wall_mask;
 
-#if 1
-    {
-      int x = ELX, y = ELY;
-      int wall_mask = laser.wall_mask;
-
-      ScanLaser();
-      DrawLaser(0, DL_LASER_ENABLED);
-
-      PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
-
-      Tile[x][y] = Tile[x][y] - EL_WALL_AMOEBA + EL_WALL_CHANGING;
-      Store[x][y] = EL_WALL_AMOEBA;
-      Store2[x][y] = wall_mask;
-
-      return;
-    }
-#endif
-
-    DrawWallsAnimation_MM(dx, dy, de, 4, dm);
     ScanLaser();
     DrawLaser(0, DL_LASER_ENABLED);
 
-    PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
+    PlayLevelSound_MM(x, y, element, MM_ACTION_GROWING);
 
-    for (i = 4; i >= 0; i--)
-    {
-      DrawWallsAnimation_MM(dx, dy, de, i, dm);
-
-      BackToFront();
-      Delay_WithScreenUpdates(20);
-    }
-
-    DrawLaser(0, DL_LASER_ENABLED);
+    Tile[x][y] = Tile[x][y] - EL_WALL_AMOEBA_BASE + EL_WALL_CHANGING_BASE;
+    Store[x][y] = EL_WALL_AMOEBA_BASE;
+    Store2[x][y] = wall_mask;
 
     return;
   }
@@ -3644,45 +4038,46 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
   if (element == EL_FUEL_FULL && CT > 10)
   {
-    for (i = game_mm.energy_left; i <= MAX_LASER_ENERGY; i+=2)
+    int num_init_game_frames = INIT_GAME_ACTIONS_DELAY;
+    int start = num_init_game_frames * game_mm.energy_left / native_mm_level.time;
+
+    for (i = start; i <= num_init_game_frames; i++)
     {
-#if 0
-      BlitBitmap(pix[PIX_DOOR], drawto,
-                DOOR_GFX_PAGEX4 + XX_ENERGY,
-                DOOR_GFX_PAGEY1 + YY_ENERGY + ENERGY_YSIZE - i,
-                ENERGY_XSIZE, i, DX_ENERGY,
-                DY_ENERGY + ENERGY_YSIZE - i);
-#endif
+      if (i == num_init_game_frames)
+       StopSound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+      else if (setup.sound_loops)
+       PlaySoundLoop_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+      else
+       PlaySound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
 
-      redraw_mask |= REDRAW_DOOR_1;
-      BackToFront();
+      game_mm.energy_left = native_mm_level.time * i / num_init_game_frames;
 
-      Delay_WithScreenUpdates(20);
+      UpdateAndDisplayGameControlValues();
+
+      BackToFront_MM();
     }
 
-    game_mm.energy_left = MAX_LASER_ENERGY;
-    Tile[ELX][ELY] = EL_FUEL_EMPTY;
+    Tile[ELX][ELY] = laser.dest_element = EL_FUEL_EMPTY;
+
     DrawField_MM(ELX, ELY);
 
     DrawLaser(0, DL_LASER_ENABLED);
 
     return;
   }
-
-  return;
 }
 
-void GameActions_MM(struct MouseActionInfo action, boolean warp_mode)
+void GameActions_MM(struct MouseActionInfo action)
 {
   boolean element_clicked = ClickElement(action.lx, action.ly, action.button);
   boolean button_released = (action.button == MB_RELEASED);
 
-  GameActions_MM_Ext(action, warp_mode);
+  GameActions_MM_Ext();
 
   CheckSingleStepMode_MM(element_clicked, button_released);
 }
 
-void MovePacMen(void)
+static void MovePacMen(void)
 {
   int mx, my, ox, oy, nx, ny;
   int element;
@@ -3758,7 +4153,7 @@ void MovePacMen(void)
     }
 
     DrawField_MM(nx, ny);
-    BackToFront();
+    BackToFront_MM();
 
     if (!laser.fuse_off)
     {
@@ -3799,35 +4194,6 @@ static void InitMovingField_MM(int x, int y, int direction)
     Tile[newx][newy] = EL_BLOCKED;
 }
 
-static void Moving2Blocked_MM(int x, int y, int *goes_to_x, int *goes_to_y)
-{
-  int direction = MovDir[x][y];
-  int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
-  int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
-
-  *goes_to_x = newx;
-  *goes_to_y = newy;
-}
-
-static void Blocked2Moving_MM(int x, int y,
-                             int *comes_from_x, int *comes_from_y)
-{
-  int oldx = x, oldy = y;
-  int direction = MovDir[x][y];
-
-  if (direction == MV_LEFT)
-    oldx++;
-  else if (direction == MV_RIGHT)
-    oldx--;
-  else if (direction == MV_UP)
-    oldy++;
-  else if (direction == MV_DOWN)
-    oldy--;
-
-  *comes_from_x = oldx;
-  *comes_from_y = oldy;
-}
-
 static int MovingOrBlocked2Element_MM(int x, int y)
 {
   int element = Tile[x][y];
@@ -3836,7 +4202,7 @@ static int MovingOrBlocked2Element_MM(int x, int y)
   {
     int oldx, oldy;
 
-    Blocked2Moving_MM(x, y, &oldx, &oldy);
+    Blocked2Moving(x, y, &oldx, &oldy);
 
     return Tile[oldx][oldy];
   }
@@ -3844,16 +4210,6 @@ static int MovingOrBlocked2Element_MM(int x, int y)
   return element;
 }
 
-#if 0
-static void RemoveField(int x, int y)
-{
-  Tile[x][y] = EL_EMPTY;
-  MovPos[x][y] = 0;
-  MovDir[x][y] = 0;
-  MovDelay[x][y] = 0;
-}
-#endif
-
 static void RemoveMovingField_MM(int x, int y)
 {
   int oldx = x, oldy = y, newx = x, newy = y;
@@ -3863,13 +4219,13 @@ static void RemoveMovingField_MM(int x, int y)
 
   if (IS_MOVING(x, y))
   {
-    Moving2Blocked_MM(x, y, &newx, &newy);
+    Moving2Blocked(x, y, &newx, &newy);
     if (Tile[newx][newy] != EL_BLOCKED)
       return;
   }
   else if (Tile[x][y] == EL_BLOCKED)
   {
-    Blocked2Moving_MM(x, y, &oldx, &oldy);
+    Blocked2Moving(x, y, &oldx, &oldy);
     if (!IS_MOVING(oldx, oldy))
       return;
   }
@@ -3883,44 +4239,6 @@ static void RemoveMovingField_MM(int x, int y)
   DrawLevelField_MM(newx, newy);
 }
 
-void PlaySoundLevel(int x, int y, int sound_nr)
-{
-  int sx = SCREENX(x), sy = SCREENY(y);
-  int volume, stereo;
-  int silence_distance = 8;
-
-  if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
-      (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
-    return;
-
-  if (!IN_LEV_FIELD(x, y) ||
-      sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
-      sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
-    return;
-
-  volume = SOUND_MAX_VOLUME;
-
-#ifndef MSDOS
-  stereo = (sx - SCR_FIELDX/2) * 12;
-#else
-  stereo = SOUND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
-  if (stereo > SOUND_MAX_RIGHT)
-    stereo = SOUND_MAX_RIGHT;
-  if (stereo < SOUND_MAX_LEFT)
-    stereo = SOUND_MAX_LEFT;
-#endif
-
-  if (!IN_SCR_FIELD(sx, sy))
-  {
-    int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
-    int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
-
-    volume -= volume * (dx > dy ? dx : dy) / silence_distance;
-  }
-
-  PlaySoundExt(sound_nr, volume, stereo, SND_CTRL_PLAY_SOUND);
-}
-
 static void RaiseScore_MM(int value)
 {
   game_mm.score += value;
@@ -3961,7 +4279,7 @@ void RaiseScoreElement_MM(int element)
 // Mirror Magic game engine snapshot handling functions
 // ----------------------------------------------------------------------------
 
-void SaveEngineSnapshotValues_MM(ListNode **buffers)
+void SaveEngineSnapshotValues_MM(void)
 {
   int x, y;
 
@@ -3976,7 +4294,6 @@ void SaveEngineSnapshotValues_MM(ListNode **buffers)
       engine_snapshot_mm.Hit[x][y]   = Hit[x][y];
       engine_snapshot_mm.Box[x][y]   = Box[x][y];
       engine_snapshot_mm.Angle[x][y] = Angle[x][y];
-      engine_snapshot_mm.Frame[x][y] = Frame[x][y];
     }
   }
 
@@ -4019,7 +4336,6 @@ void LoadEngineSnapshotValues_MM(void)
       Hit[x][y]   = engine_snapshot_mm.Hit[x][y];
       Box[x][y]   = engine_snapshot_mm.Box[x][y];
       Angle[x][y] = engine_snapshot_mm.Angle[x][y];
-      Frame[x][y] = engine_snapshot_mm.Frame[x][y];
     }
   }
 
index b223c73059d2a60b15eabf06af0919314235048c..e499cefaf3dbeb70cc5f3ab657527219436a94fb 100644 (file)
 
 #include "main_mm.h"
 
-
-void TurnRound(int, int);
-
-void PlaySoundLevel(int, int, int);
-
-void AddLaserEdge(int, int);
-void AddDamagedField(int, int);
-void ScanLaser(void);
-void DrawLaser(int, int);
-boolean HitElement(int, int);
-boolean HitOnlyAnEdge(int, int);
-boolean HitPolarizer(int, int);
-boolean HitBlock(int, int);
-boolean HitLaserSource(int, int);
-boolean HitLaserDestination(int, int);
-boolean HitReflectingWalls(int, int);
-boolean HitAbsorbingWalls(int, int);
-void RotateMirror(int, int, int);
-boolean ObjHit(int, int, int);
-void DeletePacMan(int, int);
-
-void ColorCycling(void);
-void MovePacMen(void);
-
 #endif
index 0fe4c9fca1ef23892709707b926b3df946d3df92..b7dcbe35ebcfb424bacc353ca5164cbb728cbb8f 100644 (file)
 #include "mm_main.h"
 
 
+Bitmap *drawto_mm;
+
 struct EngineSnapshotInfo_MM engine_snapshot_mm;
 
 
+void InitGfxBuffers_MM(void)
+{
+  ReCreateBitmap(&drawto_mm, video.width, video.height);
+}
+
 unsigned int InitEngineRandom_MM(int seed)
 {
   return InitEngineRandom(seed);
@@ -24,7 +31,7 @@ unsigned int InitEngineRandom_MM(int seed)
 
 void InitElementProperties_MM(void)
 {
-  int i,j;
+  int i, j;
 
   static int ep_grid[] =
   {
@@ -171,6 +178,15 @@ void InitElementProperties_MM(void)
   };
   static int ep_pacman_num = sizeof(ep_pacman) / sizeof(int);
 
+  static int ep_envelope[] =
+  {
+    EL_ENVELOPE_1,
+    EL_ENVELOPE_2,
+    EL_ENVELOPE_3,
+    EL_ENVELOPE_4,
+  };
+  static int ep_envelope_num = sizeof(ep_envelope) / sizeof(int);
+
   static long ep_bit[] =
   {
     EP_BIT_GRID,
@@ -186,6 +202,7 @@ void InitElementProperties_MM(void)
     EP_BIT_INACTIVE,
     EP_BIT_WALL,
     EP_BIT_PACMAN,
+    EP_BIT_ENVELOPE,
   };
   static int *ep_array[] =
   {
@@ -202,6 +219,7 @@ void InitElementProperties_MM(void)
     ep_inactive,
     ep_wall,
     ep_pacman,
+    ep_envelope,
   };
   static int *ep_num[] =
   {
@@ -218,6 +236,7 @@ void InitElementProperties_MM(void)
     &ep_inactive_num,
     &ep_wall_num,
     &ep_pacman_num,
+    &ep_envelope_num,
   };
   static int num_properties = sizeof(ep_num) / sizeof(int *);
 
@@ -239,7 +258,3 @@ void mm_open_all(void)
 {
   InitElementProperties_MM();
 }
-
-void mm_close_all(void)
-{
-}
index 77f7e3a25e764f25e90491b45aa2eb7980e7648b..048d8fd3240c157ae8b2231706def056f059a7ed 100644 (file)
@@ -28,8 +28,10 @@ unsigned int Elementeigenschaften[MAX_ELEMENTS];
 
 struct LaserInfo       laser;
 
-short          LX,LY, XS,YS, ELX,ELY;
-short          CT,Ct;
+short          LX, LY;
+short          XS, YS;
+short          ELX, ELY;
+short          CT, Ct;
 
 int            dSX, dSY;
 int            cSX, cSY;
index af5b832faaaacd3e4e5d40b519b18a33e123f0e4..684647ce12ea77ca52aff8fc88a27288e7fb452f 100644 (file)
@@ -48,6 +48,7 @@
 #define EP_BIT_INACTIVE                (1 << 11)
 #define EP_BIT_WALL            (1 << 12)
 #define EP_BIT_PACMAN          (1 << 13)
+#define EP_BIT_ENVELOPE                (1 << 14)
 
 #define IS_GRID(e)             (Elementeigenschaften[e] & EP_BIT_GRID)
 #define IS_MCDUFFIN(e)         (Elementeigenschaften[e] & EP_BIT_MCDUFFIN)
@@ -63,6 +64,7 @@
 #define IS_INACTIVE(e)         (Elementeigenschaften[e] & EP_BIT_INACTIVE)
 #define IS_MM_WALL(e)          (Elementeigenschaften[e] & EP_BIT_WALL)
 #define IS_PACMAN(e)           (Elementeigenschaften[e] & EP_BIT_PACMAN)
+#define IS_ENVELOPE(e)         (Elementeigenschaften[e] & EP_BIT_ENVELOPE)
 
 #define IS_WALL_STEEL(e)       ((e) >= EL_WALL_STEEL_START &&          \
                                 (e) <= EL_WALL_STEEL_END)
                                 (e) <= EL_DF_MIRROR_END)
 #define IS_DF_MIRROR_AUTO(e)   ((e) >= EL_DF_MIRROR_AUTO_START &&      \
                                 (e) <= EL_DF_MIRROR_AUTO_END)
+#define IS_DF_MIRROR_FIXED(e)  ((e) >= EL_DF_MIRROR_FIXED_START &&     \
+                                (e) <= EL_DF_MIRROR_FIXED_END)
+#define IS_DF_SLOPE(e)         ((e) >= EL_DF_SLOPE_START &&            \
+                                (e) <= EL_DF_SLOPE_END)
 #define IS_LASER(e)            ((e) >= EL_LASER_START &&               \
                                 (e) <= EL_LASER_END)
 #define IS_RECEIVER(e)         ((e) >= EL_RECEIVER_START &&            \
                                 (e) == EL_BOMB ||                      \
                                 IS_WALL_AMOEBA(e))
 
-#define CAN_MOVE(e)            ((e) == EL_PACMAN)
-#define IS_FREE(x,y)            (Tile[x][y] == EL_EMPTY)
+#define IS_ABSORBING_BLOCK(e)  (IS_WALL_WOOD(e) ||                     \
+                                IS_DF_WALL_WOOD(e) ||                  \
+                                (e) == EL_BLOCK_WOOD ||                \
+                                (e) == EL_GATE_WOOD ||                 \
+                                (e) == EL_EXIT_CLOSED ||               \
+                                (e) == EL_EXIT_OPEN)
 
-#define IS_MOVING(x,y)          (MovPos[x][y] != 0)
-#define IS_BLOCKED(x,y)         (Tile[x][y] == EL_BLOCKED)
-#define IS_DRAWABLE(e)          ((e) < EL_BLOCKED)
-#define IS_NOT_DRAWABLE(e)      ((e) >= EL_BLOCKED)
+#define IS_ENVELOPE_OPENING(e) ((e) >= EL_ENVELOPE_OPENING_START &&    \
+                                (e) <= EL_ENVELOPE_OPENING_END)
 
-#define PLAYERINFO(x,y)         (&stored_player[StorePlayer[x][y]-EL_SPIELER1])
+#define ENVELOPE_NR(e)         ((e) - EL_ENVELOPE_1)
+#define ENVELOPE_OPENING_NR(e) ((e) - EL_ENVELOPE_1_OPENING)
 
-#define WALL_BASE(e)           ((e) & 0xfff0)
-#define WALL_BITS(e)           ((e) & 0x000f)
+#define CAN_MOVE(e)            ((e) == EL_PACMAN)
+#define IS_FREE(x, y)          (Tile[x][y] == EL_EMPTY)
 
-// Bitmaps with graphic file
-#define PIX_BACK               0
-#define PIX_DOOR               1
-#define PIX_TOONS              2
-#define PIX_DF                 3
-#define        PIX_BIGFONT             4
-#define PIX_SMALLFONT          5
-#define PIX_MEDIUMFONT         6
-// Bitmaps without graphic file
-#define PIX_DB_DOOR            7
+#define IS_MOVING(x, y)                (MovPos[x][y] != 0)
+#define IS_BLOCKED(x, y)       (Tile[x][y] == EL_BLOCKED)
+#define IS_DRAWABLE(e)         ((e) < EL_BLOCKED)
+#define IS_NOT_DRAWABLE(e)     ((e) >= EL_BLOCKED)
 
-#define NUM_PICTURES           7
-#define NUM_BITMAPS            8
+#define WALL_BASE(e)           ((e) & 0xfff0)
+#define WALL_BITS(e)           ((e) & 0x000f)
 
 // boundaries of arrays etc.
 #define MAX_PLAYER_NAME_LEN    10
 #define LEVEL_SCORE_ELEMENTS   16      // level elements with score
 
 
-extern DrawBuffer      *drawto_field;
+extern DrawBuffer      *drawto_mm;
+extern DrawBuffer      *bitmap_db_field;
 
 extern int             game_status;
 extern boolean         level_editor_test_game;
@@ -203,7 +207,13 @@ extern short               StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short           Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern boolean         Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short           AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short           AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA];
+extern short           AmoebaCnt[MAX_NUM_AMOEBA];
+extern short           AmoebaCnt2[MAX_NUM_AMOEBA];
+extern short           ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+extern int             GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
 extern unsigned int    Elementeigenschaften[MAX_ELEMENTS];
 
 extern int             level_nr;
@@ -239,61 +249,6 @@ extern short               Sign[16];
 extern char           *element_info[];
 extern int             num_element_info;
 
-// often used screen positions
-#define DX                     534
-#define DY                     60
-#define EX                     DX
-#define EY                     (DY + 178)
-#define TILEX                  TILESIZE
-#define TILEY                  TILESIZE
-#define MINI_TILESIZE          (TILESIZE / 2)
-#define MINI_TILEX             (TILEX / 2)
-#define MINI_TILEY             (TILEY / 2)
-#define MICRO_TILEX            (TILEX / 4)
-#define MICRO_TILEY            (TILEY / 4)
-#define MICRO_WALLX            (TILEX / 8)
-#define MICRO_WALLY            (TILEY / 8)
-#define MIDPOSX                        (SCR_FIELDX / 2)
-#define MIDPOSY                        (SCR_FIELDY / 2)
-#define DXSIZE                 100
-#define DYSIZE                 280
-#define VXSIZE                 DXSIZE
-#define VYSIZE                 100
-#define EXSIZE                 DXSIZE
-#define EYSIZE                 (VXSIZE + 44)
-#define FULL_SXSIZE            (2 + SXSIZE + 2)
-#define FULL_SYSIZE            (2 + SYSIZE + 2)
-#define MICROLEV_XPOS          (SX + 12 * TILEX)
-#define MICROLEV_YPOS          (SY +  6 * TILEY)
-#define MICROLEV_XSIZE         (STD_LEV_FIELDX * MICRO_TILEX)
-#define MICROLEV_YSIZE         (STD_LEV_FIELDY * MICRO_TILEY)
-#define MICROLABEL_XPOS                (SY)
-#define MICROLABEL_YPOS                (SY + 352)
-#define MICROLABEL_XSIZE       (SXSIZE)
-#define MICROLABEL_YSIZE       (FONT4_YSIZE)
-
-#define GFX_STARTX             SX
-#define GFX_STARTY             SY
-#define MINI_GFX_STARTX                (SX + 8 * TILEX)
-#define MINI_GFX_STARTY                (SY + 6 * TILEY)
-#define MICRO_GFX_STARTX       (MINI_GFX_STARTX + 8 * MINI_TILEX)
-#define MICRO_GFX_STARTY       (MINI_GFX_STARTY + 6 * MINI_TILEY)
-#define GFX_PER_LINE           16
-#define MINI_GFX_PER_LINE      GFX_PER_LINE
-#define MICRO_GFX_PER_LINE     GFX_PER_LINE
-
-#define MINI_DF_STARTX         (8 * TILEX)
-#define MINI_DF_STARTY         (8 * TILEY)
-#define MICRO_DF_STARTX                (MINI_DF_STARTX + 8 * MINI_TILEX)
-#define MICRO_DF_STARTY                (MINI_DF_STARTY + 8 * MINI_TILEY)
-#define DF_PER_LINE            16
-#define MINI_DF_PER_LINE       DF_PER_LINE
-#define MICRO_DF_PER_LINE      DF_PER_LINE
-
-#define MICRO_FONT_STARTX      (MICRO_DF_STARTX + 8 * MICRO_TILEX)
-#define MICRO_FONT_STARTY      (MICRO_DF_STARTY + 8 * MICRO_TILEY)
-#define MICRO_FONT_PER_LINE    8
-
 // wall positions (that can be OR'ed together)
 #define WALL_TOPLEFT           1
 #define WALL_TOPRIGHT          2
@@ -350,31 +305,22 @@ extern int                num_element_info;
 #define EL_KETTLE              29
 #define EL_BOMB                        30
 #define EL_PRISM               31
-#define EL_WALL_START          32
-#define EL_WALL_EMPTY          EL_WALL_START
-#define EL_WALL_00             EL_WALL_START
-#define EL_WALL_STEEL          EL_WALL_00
-#define EL_WALL_STEEL_START    EL_WALL_00
-#define EL_WALL_15             47
-#define EL_WALL_STEEL_END      EL_WALL_15
-#define EL_WALL_16             48
-#define EL_WALL_WOOD           EL_WALL_16
-#define EL_WALL_WOOD_START     EL_WALL_16
-#define EL_WALL_31             63
-#define EL_WALL_WOOD_END       EL_WALL_31
-#define EL_WALL_32             64
-#define EL_WALL_ICE            EL_WALL_32
-#define EL_WALL_ICE_START      EL_WALL_32
-#define EL_WALL_47             79
-#define EL_WALL_ICE_END                EL_WALL_47
-#define EL_WALL_48             80
-#define EL_WALL_AMOEBA         EL_WALL_48
-#define EL_WALL_AMOEBA_START   EL_WALL_48
-#define EL_WALL_63             95
-#define EL_WALL_AMOEBA_END     EL_WALL_63
-#define EL_WALL_END            EL_WALL_63
+#define EL_WALL_START          EL_WALL_STEEL_START
+#define EL_WALL_STEEL_BASE     32
+#define EL_WALL_STEEL_START    (EL_WALL_STEEL_BASE + 0)
+#define EL_WALL_STEEL_END      (EL_WALL_STEEL_BASE + 15)
+#define EL_WALL_WOOD_BASE      48
+#define EL_WALL_WOOD_START     (EL_WALL_WOOD_BASE + 0)
+#define EL_WALL_WOOD_END       (EL_WALL_WOOD_BASE + 15)
+#define EL_WALL_ICE_BASE       64
+#define EL_WALL_ICE_START      (EL_WALL_ICE_BASE + 0)
+#define EL_WALL_ICE_END                (EL_WALL_ICE_BASE + 15)
+#define EL_WALL_AMOEBA_BASE    80
+#define EL_WALL_AMOEBA_START   (EL_WALL_AMOEBA_BASE + 0)
+#define EL_WALL_AMOEBA_END     (EL_WALL_AMOEBA_BASE + 15)
+#define EL_WALL_END            EL_WALL_AMOEBA_END
 #define EL_BLOCK_WOOD          96
-#define EL_BALL_GRAY           97
+#define EL_GRAY_BALL           97
 #define EL_BEAMER_START                98
 #define EL_BEAMER_00           (EL_BEAMER_START + 0)
 #define EL_BEAMER_01           (EL_BEAMER_START + 1)
@@ -445,8 +391,12 @@ extern int         num_element_info;
 #define EL_GRID_WOOD_03                (EL_GRID_WOOD_START + 3)
 #define EL_GRID_WOOD_END       EL_GRID_WOOD_03
 #define EL_FUEL_EMPTY          155
+#define EL_ENVELOPE_1          156
+#define EL_ENVELOPE_2          157
+#define EL_ENVELOPE_3          158
+#define EL_ENVELOPE_4          159
 
-#define EL_MM_END_1            155
+#define EL_MM_END_1            159
 
 #define EL_CHAR_START          160
 #define EL_CHAR_ASCII0         (EL_CHAR_START - 32)
@@ -533,14 +483,15 @@ extern int                num_element_info;
 #define EL_GRID_STEEL_FIXED_07 (EL_GRID_STEEL_FIXED_START + 7) // 157.5°
 #define EL_GRID_STEEL_FIXED_END        EL_GRID_STEEL_FIXED_07
 
-#define EL_DF_WALL_WOOD                272
-#define EL_DF_WALL_START       EL_DF_WALL_WOOD_START
-#define EL_DF_WALL_WOOD_START  (EL_DF_WALL_WOOD + 0)
-#define EL_DF_WALL_WOOD_END    (EL_DF_WALL_WOOD + 15)
+#define EL_DF_WALL_WOOD_BASE   272
+#define EL_DF_WALL_WOOD_START  (EL_DF_WALL_WOOD_BASE + 0)
+#define EL_DF_WALL_WOOD_END    (EL_DF_WALL_WOOD_BASE + 15)
+
+#define EL_DF_WALL_STEEL_BASE  288
+#define EL_DF_WALL_STEEL_START (EL_DF_WALL_STEEL_BASE + 0)
+#define EL_DF_WALL_STEEL_END   (EL_DF_WALL_STEEL_BASE + 15)
 
-#define EL_DF_WALL_STEEL       288
-#define EL_DF_WALL_STEEL_START (EL_DF_WALL_STEEL + 0)
-#define EL_DF_WALL_STEEL_END   (EL_DF_WALL_STEEL + 15)
+#define EL_DF_WALL_START       EL_DF_WALL_WOOD_START
 #define EL_DF_WALL_END         EL_DF_WALL_STEEL_END
 
 #define EL_DF_EMPTY            304
@@ -629,28 +580,64 @@ extern int                num_element_info;
 #define EL_MCDUFFIN            420
 #define EL_PACMAN              421
 #define EL_FUSE_OFF            422
-#define EL_STEEL_WALL          423
-#define EL_WOODEN_WALL         424
-#define EL_ICE_WALL            425
-#define EL_AMOEBA_WALL         426
+#define EL_WALL_STEEL          423
+#define EL_WALL_WOOD           424
+#define EL_WALL_ICE            425
+#define EL_WALL_AMOEBA         426
 #define EL_LASER               427
 #define EL_RECEIVER            428
-#define EL_DF_STEEL_WALL       429
-#define EL_DF_WOODEN_WALL      430
-
-#define EL_MM_END_2            430
+#define EL_DF_WALL_STEEL       429
+#define EL_DF_WALL_WOOD                430
+
+#define EL_DF_MIRROR_FIXED_START 431
+#define EL_DF_MIRROR_FIXED_00  (EL_DF_MIRROR_FIXED_START + 0)
+#define EL_DF_MIRROR_FIXED_01  (EL_DF_MIRROR_FIXED_START + 1)
+#define EL_DF_MIRROR_FIXED_02  (EL_DF_MIRROR_FIXED_START + 2)
+#define EL_DF_MIRROR_FIXED_03  (EL_DF_MIRROR_FIXED_START + 3)
+#define EL_DF_MIRROR_FIXED_04  (EL_DF_MIRROR_FIXED_START + 4)
+#define EL_DF_MIRROR_FIXED_05  (EL_DF_MIRROR_FIXED_START + 5)
+#define EL_DF_MIRROR_FIXED_06  (EL_DF_MIRROR_FIXED_START + 6)
+#define EL_DF_MIRROR_FIXED_07  (EL_DF_MIRROR_FIXED_START + 7)
+#define EL_DF_MIRROR_FIXED_08  (EL_DF_MIRROR_FIXED_START + 8)
+#define EL_DF_MIRROR_FIXED_09  (EL_DF_MIRROR_FIXED_START + 9)
+#define EL_DF_MIRROR_FIXED_10  (EL_DF_MIRROR_FIXED_START + 10)
+#define EL_DF_MIRROR_FIXED_11  (EL_DF_MIRROR_FIXED_START + 11)
+#define EL_DF_MIRROR_FIXED_12  (EL_DF_MIRROR_FIXED_START + 12)
+#define EL_DF_MIRROR_FIXED_13  (EL_DF_MIRROR_FIXED_START + 13)
+#define EL_DF_MIRROR_FIXED_14  (EL_DF_MIRROR_FIXED_START + 14)
+#define EL_DF_MIRROR_FIXED_15  (EL_DF_MIRROR_FIXED_START + 15)
+#define EL_DF_MIRROR_FIXED_END EL_DF_MIRROR_FIXED_15
+
+#define EL_DF_SLOPE_START       447
+#define EL_DF_SLOPE_00         (EL_DF_SLOPE_START + 0)
+#define EL_DF_SLOPE_01         (EL_DF_SLOPE_START + 1)
+#define EL_DF_SLOPE_02         (EL_DF_SLOPE_START + 2)
+#define EL_DF_SLOPE_03         (EL_DF_SLOPE_START + 3)
+#define EL_DF_SLOPE_END                EL_DF_SLOPE_03
+
+#define EL_MM_END_2            450
 #define EL_MM_END              EL_MM_END_2
 
 // "real" (and therefore drawable) runtime elements
 #define EL_EXIT_OPENING                500
 #define EL_EXIT_CLOSING                501
-#define EL_GRAY_BALL_OPENING   502
-#define EL_ICE_WALL_SHRINKING  503
-#define EL_AMOEBA_WALL_GROWING 504
-
-#define EL_WALL_CHANGING       512
-#define EL_WALL_CHANGING_START (EL_WALL_CHANGING + 0)
-#define EL_WALL_CHANGING_END   (EL_WALL_CHANGING + 15)
+#define EL_GRAY_BALL_ACTIVE    502
+#define EL_GRAY_BALL_OPENING   503
+#define EL_WALL_ICE_SHRINKING  504
+#define EL_WALL_AMOEBA_GROWING 505
+#define EL_BOMB_ACTIVE         506
+#define EL_MINE_ACTIVE         507
+#define EL_ENVELOPE_1_OPENING  508
+#define EL_ENVELOPE_2_OPENING  509
+#define EL_ENVELOPE_3_OPENING  510
+#define EL_ENVELOPE_4_OPENING  511
+
+#define EL_ENVELOPE_OPENING_START      EL_ENVELOPE_1_OPENING
+#define EL_ENVELOPE_OPENING_END                EL_ENVELOPE_4_OPENING
+
+#define EL_WALL_CHANGING_BASE  512
+#define EL_WALL_CHANGING_START (EL_WALL_CHANGING_BASE + 0)
+#define EL_WALL_CHANGING_END   (EL_WALL_CHANGING_BASE + 15)
 
 #define EL_FIRST_RUNTIME_EL    EL_EXIT_OPENING
 
@@ -659,18 +646,6 @@ extern int         num_element_info;
 #define EL_EXPLODING_OPAQUE    601
 #define EL_EXPLODING_TRANSP    602
 
-// dummy elements (never used as game elements, only used as graphics)
-#define EL_MM_MASK_MCDUFFIN_RIGHT      700
-#define EL_MM_MASK_MCDUFFIN_UP         701
-#define EL_MM_MASK_MCDUFFIN_LEFT       702
-#define EL_MM_MASK_MCDUFFIN_DOWN       703
-#define EL_MM_MASK_GRID_1              704
-#define EL_MM_MASK_GRID_2              705
-#define EL_MM_MASK_GRID_3              706
-#define EL_MM_MASK_GRID_4              707
-#define EL_MM_MASK_RECTANGE            708
-#define EL_MM_MASK_CIRCLE              709
-
 
 // game graphics:
 //       0 -  191: graphics from "MirrorScreen"
@@ -680,324 +655,6 @@ extern int                num_element_info;
 
 #define IMG_EMPTY              IMG_EMPTY_SPACE
 
-#define GFX_START_MIRRORSCREEN 0
-#define GFX_END_MIRRORSCREEN   191
-#define GFX_START_PSEUDO       192
-#define GFX_END_PSEUDO         255
-#define GFX_START_MIRRORFONT   256
-#define GFX_END_MIRRORFONT     511
-#define GFX_START_MIRRORDF     512
-#define GFX_END_MIRRORDF       767
-
-#define NUM_TILES              512
-
-// graphics from "MirrorScreen"
-#define GFX_EMPTY              (-1)
-// row 0 (0)
-#define GFX_MIRROR_START       0
-#define GFX_MIRROR             GFX_MIRROR_START
-#define GFX_MIRROR_00          (GFX_MIRROR_START + 0)
-#define GFX_MIRROR_01          (GFX_MIRROR_START + 1)
-#define GFX_MIRROR_02          (GFX_MIRROR_START + 2)
-#define GFX_MIRROR_03          (GFX_MIRROR_START + 3)
-#define GFX_MIRROR_04          (GFX_MIRROR_START + 4)
-#define GFX_MIRROR_05          (GFX_MIRROR_START + 5)
-#define GFX_MIRROR_06          (GFX_MIRROR_START + 6)
-#define GFX_MIRROR_07          (GFX_MIRROR_START + 7)
-#define GFX_MIRROR_08          (GFX_MIRROR_START + 8)
-#define GFX_MIRROR_09          (GFX_MIRROR_START + 9)
-#define GFX_MIRROR_10          (GFX_MIRROR_START + 10)
-#define GFX_MIRROR_11          (GFX_MIRROR_START + 11)
-#define GFX_MIRROR_12          (GFX_MIRROR_START + 12)
-#define GFX_MIRROR_13          (GFX_MIRROR_START + 13)
-#define GFX_MIRROR_14          (GFX_MIRROR_START + 14)
-#define GFX_MIRROR_15          (GFX_MIRROR_START + 15)
-#define GFX_MIRROR_END         GFX_MIRROR_15
-// row 1 (16)
-#define GFX_GRID_STEEL_START   16
-#define GFX_GRID_STEEL         GFX_GRID_STEEL_START
-#define GFX_GRID_STEEL_00      (GFX_GRID_STEEL_START + 0)
-#define GFX_GRID_STEEL_01      (GFX_GRID_STEEL_START + 1)
-#define GFX_GRID_STEEL_02      (GFX_GRID_STEEL_START + 2)
-#define GFX_GRID_STEEL_03      (GFX_GRID_STEEL_START + 3)
-#define GFX_MCDUFFIN_START     20
-#define GFX_MCDUFFIN           GFX_MCDUFFIN_START
-#define GFX_MCDUFFIN_RIGHT     (GFX_MCDUFFIN_START + 0)
-#define GFX_MCDUFFIN_UP                (GFX_MCDUFFIN_START + 1)
-#define GFX_MCDUFFIN_LEFT      (GFX_MCDUFFIN_START + 2)
-#define GFX_MCDUFFIN_DOWN      (GFX_MCDUFFIN_START + 3)
-#define GFX_EXIT_CLOSED                24
-#define GFX_EXIT_OPENING_1     25
-#define GFX_EXIT_OPENING_2     26
-#define GFX_EXIT_OPEN          27
-#define GFX_KETTLE             28
-#define GFX_EXPLOSION_KETTLE   29
-// row 2 (32)
-#define GFX_PRISM              32
-#define GFX_WALL_SEVERAL       33
-#define GFX_WALL_ANIMATION     34
-#define GFX_BLOCK_WOOD         36
-#define GFX_BOMB               37
-#define GFX_FUSE_ON            38
-#define GFX_FUSE_OFF           39
-#define GFX_GATE_STONE         40
-#define GFX_KEY                        41
-#define GFX_LIGHTBULB_OFF      42
-#define GFX_LIGHTBULB_ON       43
-#define GFX_BALL_RED           44
-#define GFX_BALL_BLUE          45
-#define GFX_BALL_YELLOW                46
-#define GFX_BALL_GRAY          47
-// row 3 (48)
-#define GFX_BEAMER_START       48
-#define GFX_BEAMER_END         63
-// row 4 (64)
-#define GFX_PACMAN_START       64
-#define GFX_PACMAN             GFX_PACMAN_START
-#define GFX_PACMAN_RIGHT       (GFX_PACMAN_START + 0)
-#define GFX_PACMAN_UP          (GFX_PACMAN_START + 1)
-#define GFX_PACMAN_LEFT                (GFX_PACMAN_START + 2)
-#define GFX_PACMAN_DOWN                (GFX_PACMAN_START + 3)
-#define GFX_EXPLOSION_START    72
-#define GFX_EXPLOSION_SHORT    76
-#define GFX_EXPLOSION_LAST     78
-// row 5 (80)
-#define GFX_POLAR_START                80
-#define GFX_POLAR_END          95
-// row 6 (96)
-#define GFX_POLAR_CROSS_START  96
-#define GFX_POLAR_CROSS                GFX_POLAR_CROSS_START
-#define GFX_POLAR_CROSS_00     (GFX_POLAR_CROSS_START + 0)
-#define GFX_POLAR_CROSS_01     (GFX_POLAR_CROSS_START + 1)
-#define GFX_POLAR_CROSS_02     (GFX_POLAR_CROSS_START + 2)
-#define GFX_POLAR_CROSS_03     (GFX_POLAR_CROSS_START + 3)
-#define GFX_MIRROR_FIXED_START 100
-#define GFX_MIRROR_FIXED       GFX_MIRROR_FIXED_START
-#define GFX_MIRROR_FIXED_00    (GFX_MIRROR_FIXED_START + 0)
-#define GFX_MIRROR_FIXED_01    (GFX_MIRROR_FIXED_START + 1)
-#define GFX_MIRROR_FIXED_02    (GFX_MIRROR_FIXED_START + 2)
-#define GFX_MIRROR_FIXED_03    (GFX_MIRROR_FIXED_START + 3)
-// row 7 (112)
-#define GFX_BLOCK_STONE                112
-#define GFX_GATE_WOOD          113
-#define GFX_FUEL_FULL          114
-#define GFX_FUEL_EMPTY         115
-#define GFX_GRID_WOOD_00       116
-#define GFX_GRID_WOOD_01       117
-#define GFX_GRID_WOOD_02       118
-#define GFX_GRID_WOOD_03       119
-// row 8 (128)
-#define GFX_ARROW_BLUE_LEFT    128
-#define GFX_ARROW_BLUE_RIGHT   129
-#define GFX_ARROW_BLUE_UP      130
-#define GFX_ARROW_BLUE_DOWN    131
-#define GFX_ARROW_RED_LEFT     132
-#define GFX_ARROW_RED_RIGHT    133
-#define GFX_ARROW_RED_UP       134
-#define GFX_ARROW_RED_DOWN     135
-// row 9 (144)
-#define GFX_SCROLLBAR_BLUE     144
-#define GFX_SCROLLBAR_RED      145
-// row 10 (160)
-#define GFX_MASK_CIRCLE                160
-#define GFX_MASK_RECTANGLE     161
-#define GFX_MASK_RECTANGLE2    162
-#define GFX_MASK_RECTANGLE3    163
-#define GFX_MASK_GRID_00       164
-#define GFX_MASK_GRID_01       165
-#define GFX_MASK_GRID_02       166
-#define GFX_MASK_GRID_03       167
-// row 11 (176)
-#define GFX_MASK_MCDUFFIN_00   176
-#define GFX_MASK_MCDUFFIN_01   177
-#define GFX_MASK_MCDUFFIN_02   178
-#define GFX_MASK_MCDUFFIN_03   179
-
-// pseudo-graphics; will be mapped to other graphics
-#define GFX_WALL_STEEL         192
-#define GFX_WALL_WOOD          193
-#define GFX_WALL_ICE           194
-#define GFX_WALL_AMOEBA                195
-#define GFX_DF_WALL_STEEL      196
-#define GFX_DF_WALL_WOOD       197
-
-#define GFX_KUGEL_ROT          GFX_BALL_RED
-#define GFX_KUGEL_BLAU         GFX_BALL_BLUE
-#define GFX_KUGEL_GELB         GFX_BALL_YELLOW
-#define GFX_KUGEL_GRAU         GFX_BALL_GRAY
-
-// graphics from "MirrorFont"
-#define GFX_CHAR_START         (GFX_START_MIRRORFONT)
-#define GFX_CHAR_ASCII0                (GFX_CHAR_START - 32)
-#define GFX_CHAR_AUSRUF                (GFX_CHAR_ASCII0 + 33)
-#define GFX_CHAR_ZOLL          (GFX_CHAR_ASCII0 + 34)
-#define GFX_CHAR_DOLLAR                (GFX_CHAR_ASCII0 + 36)
-#define GFX_CHAR_PROZ          (GFX_CHAR_ASCII0 + 37)
-#define GFX_CHAR_APOSTR                (GFX_CHAR_ASCII0 + 39)
-#define GFX_CHAR_KLAMM1                (GFX_CHAR_ASCII0 + 40)
-#define GFX_CHAR_KLAMM2                (GFX_CHAR_ASCII0 + 41)
-#define GFX_CHAR_PLUS          (GFX_CHAR_ASCII0 + 43)
-#define GFX_CHAR_KOMMA         (GFX_CHAR_ASCII0 + 44)
-#define GFX_CHAR_MINUS         (GFX_CHAR_ASCII0 + 45)
-#define GFX_CHAR_PUNKT         (GFX_CHAR_ASCII0 + 46)
-#define GFX_CHAR_SLASH         (GFX_CHAR_ASCII0 + 47)
-#define GFX_CHAR_0             (GFX_CHAR_ASCII0 + 48)
-#define GFX_CHAR_9             (GFX_CHAR_ASCII0 + 57)
-#define GFX_CHAR_DOPPEL                (GFX_CHAR_ASCII0 + 58)
-#define GFX_CHAR_SEMIKL                (GFX_CHAR_ASCII0 + 59)
-#define GFX_CHAR_LT            (GFX_CHAR_ASCII0 + 60)
-#define GFX_CHAR_GLEICH                (GFX_CHAR_ASCII0 + 61)
-#define GFX_CHAR_GT            (GFX_CHAR_ASCII0 + 62)
-#define GFX_CHAR_FRAGE         (GFX_CHAR_ASCII0 + 63)
-#define GFX_CHAR_AT            (GFX_CHAR_ASCII0 + 64)
-#define GFX_CHAR_A             (GFX_CHAR_ASCII0 + 65)
-#define GFX_CHAR_Z             (GFX_CHAR_ASCII0 + 90)
-#define GFX_CHAR_AE            (GFX_CHAR_ASCII0 + 91)
-#define GFX_CHAR_OE            (GFX_CHAR_ASCII0 + 92)
-#define GFX_CHAR_UE            (GFX_CHAR_ASCII0 + 93)
-#define GFX_CHAR_COPY          (GFX_CHAR_ASCII0 + 94)
-#define GFX_CHAR_END           (GFX_CHAR_START + 79)
-
-// graphics from "MirrorDF"
-#define GFX_DF_MIRROR_00       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  0)
-#define GFX_DF_MIRROR_01       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  1)
-#define GFX_DF_MIRROR_02       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  2)
-#define GFX_DF_MIRROR_03       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  3)
-#define GFX_DF_MIRROR_04       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  4)
-#define GFX_DF_MIRROR_05       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  5)
-#define GFX_DF_MIRROR_06       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  6)
-#define GFX_DF_MIRROR_07       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  7)
-#define GFX_DF_MIRROR_08       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  8)
-#define GFX_DF_MIRROR_09       (GFX_START_MIRRORDF +  0 * DF_PER_LINE +  9)
-#define GFX_DF_MIRROR_10       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 10)
-#define GFX_DF_MIRROR_11       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 11)
-#define GFX_DF_MIRROR_12       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 12)
-#define GFX_DF_MIRROR_13       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 13)
-#define GFX_DF_MIRROR_14       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 14)
-#define GFX_DF_MIRROR_15       (GFX_START_MIRRORDF +  0 * DF_PER_LINE + 15)
-
-#define GFX_DF_MIRROR_AUTO_00  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  0)
-#define GFX_DF_MIRROR_AUTO_01  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  1)
-#define GFX_DF_MIRROR_AUTO_02  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  2)
-#define GFX_DF_MIRROR_AUTO_03  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  3)
-#define GFX_DF_MIRROR_AUTO_04  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  4)
-#define GFX_DF_MIRROR_AUTO_05  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  5)
-#define GFX_DF_MIRROR_AUTO_06  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  6)
-#define GFX_DF_MIRROR_AUTO_07  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  7)
-#define GFX_DF_MIRROR_AUTO_08  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  8)
-#define GFX_DF_MIRROR_AUTO_09  (GFX_START_MIRRORDF +  1 * DF_PER_LINE +  9)
-#define GFX_DF_MIRROR_AUTO_10  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 10)
-#define GFX_DF_MIRROR_AUTO_11  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 11)
-#define GFX_DF_MIRROR_AUTO_12  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 12)
-#define GFX_DF_MIRROR_AUTO_13  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 13)
-#define GFX_DF_MIRROR_AUTO_14  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 14)
-#define GFX_DF_MIRROR_AUTO_15  (GFX_START_MIRRORDF +  1 * DF_PER_LINE + 15)
-
-#define GFX_GRID_STEEL_FIXED_00        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  0)
-#define GFX_GRID_STEEL_FIXED_01        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  1)
-#define GFX_GRID_STEEL_FIXED_02        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  2)
-#define GFX_GRID_STEEL_FIXED_03        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  3)
-#define GFX_GRID_STEEL_FIXED_04        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  4)
-#define GFX_GRID_STEEL_FIXED_05        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  5)
-#define GFX_GRID_STEEL_FIXED_06        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  6)
-#define GFX_GRID_STEEL_FIXED_07        (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  7)
-#define GFX_GRID_STEEL_FIXED   GFX_GRID_STEEL_FIXED_00
-
-#define GFX_GRID_WOOD_FIXED_00 (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  8)
-#define GFX_GRID_WOOD_FIXED_01 (GFX_START_MIRRORDF +  2 * DF_PER_LINE +  9)
-#define GFX_GRID_WOOD_FIXED_02 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 10)
-#define GFX_GRID_WOOD_FIXED_03 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 11)
-#define GFX_GRID_WOOD_FIXED_04 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 12)
-#define GFX_GRID_WOOD_FIXED_05 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 13)
-#define GFX_GRID_WOOD_FIXED_06 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 14)
-#define GFX_GRID_WOOD_FIXED_07 (GFX_START_MIRRORDF +  2 * DF_PER_LINE + 15)
-#define GFX_GRID_WOOD_FIXED    GFX_GRID_WOOD_FIXED_00
-
-#define GFX_GRID_STEEL_AUTO_00 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  0)
-#define GFX_GRID_STEEL_AUTO_01 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  1)
-#define GFX_GRID_STEEL_AUTO_02 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  2)
-#define GFX_GRID_STEEL_AUTO_03 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  3)
-#define GFX_GRID_STEEL_AUTO_04 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  4)
-#define GFX_GRID_STEEL_AUTO_05 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  5)
-#define GFX_GRID_STEEL_AUTO_06 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  6)
-#define GFX_GRID_STEEL_AUTO_07 (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  7)
-#define GFX_GRID_STEEL_AUTO    GFX_GRID_STEEL_AUTO_00
-
-#define GFX_GRID_WOOD_AUTO_00  (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  8)
-#define GFX_GRID_WOOD_AUTO_01  (GFX_START_MIRRORDF +  3 * DF_PER_LINE +  9)
-#define GFX_GRID_WOOD_AUTO_02  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 10)
-#define GFX_GRID_WOOD_AUTO_03  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 11)
-#define GFX_GRID_WOOD_AUTO_04  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 12)
-#define GFX_GRID_WOOD_AUTO_05  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 13)
-#define GFX_GRID_WOOD_AUTO_06  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 14)
-#define GFX_GRID_WOOD_AUTO_07  (GFX_START_MIRRORDF +  3 * DF_PER_LINE + 15)
-#define GFX_GRID_WOOD_AUTO     GFX_GRID_WOOD_AUTO_00
-
-#define GFX_BEAMER_RED_START   (GFX_START_MIRRORDF +  4 * DF_PER_LINE +  0)
-#define GFX_BEAMER_RED_END     (GFX_START_MIRRORDF +  4 * DF_PER_LINE + 15)
-#define GFX_BEAMER_YELLOW_START        (GFX_START_MIRRORDF +  5 * DF_PER_LINE +  0)
-#define GFX_BEAMER_YELLOW_END  (GFX_START_MIRRORDF +  5 * DF_PER_LINE + 15)
-#define GFX_BEAMER_GREEN_START (GFX_START_MIRRORDF +  6 * DF_PER_LINE +  0)
-#define GFX_BEAMER_GREEN_END   (GFX_START_MIRRORDF +  6 * DF_PER_LINE + 15)
-#define GFX_BEAMER_BLUE_START  (GFX_START_MIRRORDF +  7 * DF_PER_LINE +  0)
-#define GFX_BEAMER_BLUE_END    (GFX_START_MIRRORDF +  7 * DF_PER_LINE + 15)
-
-#define GFX_DF_WALL_SEVERAL    (GFX_START_MIRRORDF +  8 * DF_PER_LINE +  0)
-#define GFX_REFRACTOR          (GFX_START_MIRRORDF +  8 * DF_PER_LINE +  1)
-#define GFX_CELL               (GFX_START_MIRRORDF +  8 * DF_PER_LINE +  2)
-#define GFX_MINE               (GFX_START_MIRRORDF +  8 * DF_PER_LINE +  4)
-
-#define GFX_LASER_RIGHT                (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  0)
-#define GFX_LASER_UP           (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  1)
-#define GFX_LASER_LEFT         (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  2)
-#define GFX_LASER_DOWN         (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  3)
-#define GFX_RECEIVER_RIGHT     (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  4)
-#define GFX_RECEIVER_UP                (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  5)
-#define GFX_RECEIVER_LEFT      (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  6)
-#define GFX_RECEIVER_DOWN      (GFX_START_MIRRORDF +  9 * DF_PER_LINE +  7)
-
-#define GFX_FIBRE_OPTIC_00     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  0)
-#define GFX_FIBRE_OPTIC_01     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  1)
-#define GFX_FIBRE_OPTIC_02     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  2)
-#define GFX_FIBRE_OPTIC_03     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  3)
-#define GFX_FIBRE_OPTIC_04     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  4)
-#define GFX_FIBRE_OPTIC_05     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  5)
-#define GFX_FIBRE_OPTIC_06     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  6)
-#define GFX_FIBRE_OPTIC_07     (GFX_START_MIRRORDF + 10 * DF_PER_LINE +  7)
-
-#define GFX_FIBRE_OPTIC_ED_00  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  0)
-#define GFX_FIBRE_OPTIC_ED_01  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  1)
-#define GFX_FIBRE_OPTIC_ED_02  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  2)
-#define GFX_FIBRE_OPTIC_ED_03  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  3)
-#define GFX_FIBRE_OPTIC_ED_04  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  4)
-#define GFX_FIBRE_OPTIC_ED_05  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  5)
-#define GFX_FIBRE_OPTIC_ED_06  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  6)
-#define GFX_FIBRE_OPTIC_ED_07  (GFX_START_MIRRORDF + 11 * DF_PER_LINE +  7)
-
-// the names of the sounds
-#define SND_AMOEBE             0
-#define SND_ANTIGRAV           1
-#define SND_AUTSCH             2
-#define SND_BONG               3
-#define SND_FUEL               4
-#define SND_HALLOFFAME         5
-#define SND_HOLZ               6
-#define SND_HUI                        7
-#define SND_KABUMM             8
-#define SND_KINK               9
-#define SND_KLING              10
-#define SND_LASER              11
-#define SND_OEFFNEN            12
-#define SND_QUIEK              13
-#define SND_RHYTHMLOOP         14
-#define SND_ROAAAR             15
-#define SND_SIRR               16
-#define SND_SLURP              17
-#define SND_WARNTON            18
-#define SND_WHOOSH             19
-
-#define NUM_SOUNDS             20
-
 // values for graphics/sounds action types
 #define MM_ACTION_DEFAULT      0
 #define MM_ACTION_WAITING      1
@@ -1066,8 +723,9 @@ extern int         num_element_info;
 #define ANG_RAY_270            12
 #define IS_22_5_ANGLE(angle)   ((angle) % 2)
 #define IS_90_ANGLE(angle)     (!((angle) % 4))
+#define IS_45_ANGLE(angle)     (!(((angle) + 2) % 4))
 #define IS_HORIZ_ANGLE(angle)  (!((angle) % 8))
-#define IS_VERT_ANGLE(angle)   ((angle) % 8)
+#define IS_VERT_ANGLE(angle)   (!(((angle) + 4) % 8))
 
 // mirror angles
 #define ANG_MIRROR_0           0
@@ -1090,6 +748,8 @@ extern int         num_element_info;
 #define HIT_MASK_RIGHT         (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMRIGHT)
 #define HIT_MASK_TOP           (HIT_MASK_TOPLEFT | HIT_MASK_TOPRIGHT)
 #define HIT_MASK_BOTTOM                (HIT_MASK_BOTTOMLEFT | HIT_MASK_BOTTOMRIGHT)
+#define HIT_MASK_DIAGONAL_1    (HIT_MASK_TOPLEFT  | HIT_MASK_BOTTOMRIGHT)
+#define HIT_MASK_DIAGONAL_2    (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT)
 #define HIT_MASK_ALL           (HIT_MASK_LEFT | HIT_MASK_RIGHT)
 
 // step values for rotating elements
@@ -1105,29 +765,11 @@ extern int               num_element_info;
 #define GAME_OVER_OVERLOADED   2
 #define GAME_OVER_BOMB         3
 
-// values for color_status
-#define STATIC_COLORS          0
-#define DYNAMIC_COLORS         1
-
 #define PROGRAM_VERSION_MAJOR  2
 #define PROGRAM_VERSION_MINOR  0
 #define PROGRAM_VERSION_PATCH  2
 #define PROGRAM_VERSION_STRING "2.0.2"
 
-#define PROGRAM_TITLE_STRING   "Mirror Magic II"
-#define PROGRAM_AUTHOR_STRING  "Holger Schemel"
-#define PROGRAM_RIGHTS_STRING  "Copyright ^1994-2001"
-#define PROGRAM_DOS_PORT_STRING        "DOS port based on code by Guido Schulz"
-#define PROGRAM_IDENT_STRING   PROGRAM_VERSION_STRING " " TARGET_STRING
-#define WINDOW_TITLE_STRING    PROGRAM_TITLE_STRING " " PROGRAM_IDENT_STRING
-#define WINDOW_SUBTITLE_STRING PROGRAM_RIGHTS_STRING " " PROGRAM_AUTHOR_STRING
-#define ICON_TITLE_STRING      PROGRAM_TITLE_STRING
-#define UNIX_USERDATA_DIRECTORY        ".mirrormagic"
-
-#define X11_ICON_FILENAME      "mirrormagic_icon.xbm"
-#define X11_ICONMASK_FILENAME  "mirrormagic_iconmask.xbm"
-#define MSDOS_POINTER_FILENAME "mouse.pcx"
-
 // functions for version handling
 #define MM_VERSION_IDENT(x,y,z)        VERSION_IDENT(x,y,z,0)
 #define MM_VERSION_MAJOR(x)    VERSION_PART_1(x)
@@ -1151,8 +793,4 @@ extern int         num_element_info;
                                                 PROGRAM_VERSION_MINOR, \
                                                 PROGRAM_VERSION_PATCH)
 
-// sound control
-
-#define ST(x)           (((x) - 8) * 16)
-
 #endif // MM_MAIN_H
index 21ad08144351dab725e4e6ec23be4330767a3056..9d688e14149d6c5331351d35f163dc912e158119 100644 (file)
@@ -29,8 +29,8 @@ void SetDrawtoField_MM(int mode)
   // for convenience, absolute screen position to centered level playfield
   cSX = SX + dSX;
   cSY = SY + dSY;
-  cSX2 = SX + dSX + 2; // including playfield border
-  cSY2 = SY + dSY + 2; // including playfield border
+  cSX2 = SX + dSX + 2;         // including half laser line size
+  cSY2 = SY + dSY + 2;         // including half laser line size
 
   if (mode == DRAW_TO_BACKBUFFER)
   {
@@ -41,9 +41,16 @@ void SetDrawtoField_MM(int mode)
   SetTileCursorSXSY(cSX, cSY);
 }
 
+void BackToFront_MM(void)
+{
+  BlitScreenToBitmap_MM(backbuffer);
+
+  BackToFront();
+}
+
 void ClearWindow(void)
 {
-  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+  ClearRectangle(drawto_mm, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
 
   SetDrawtoField(DRAW_TO_BACKBUFFER);
   SetDrawtoField_MM(DRAW_TO_BACKBUFFER);
@@ -58,14 +65,14 @@ void DrawGraphicAnimation_MM(int x, int y, int graphic, int frame)
 
   getGraphicSource(graphic, frame, &bitmap, &src_x, &src_y);
 
-  BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY,
+  BlitBitmap(bitmap, drawto_mm, src_x, src_y, TILEX, TILEY,
             cFX + x * TILEX, cFY + y * TILEY);
 }
 
 void DrawGraphic_MM(int x, int y, int graphic)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
     Debug("game:mm:DrawGraphic_MM", "x = %d, y = %d, graphic = %d",
          x, y, graphic);
@@ -75,7 +82,9 @@ void DrawGraphic_MM(int x, int y, int graphic)
   }
 #endif
 
-  DrawGraphicExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY, graphic);
+  int frame = getGraphicAnimationFrameXY(graphic, x, y);
+
+  DrawGraphicAnimation_MM(x, y, graphic, frame);
 
   MarkTileDirty(x, y);
 }
@@ -90,12 +99,12 @@ void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
   BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y);
 }
 
-void DrawGraphicThruMask_MM(int x, int y, int graphic)
+void DrawGraphicThruMask_MM(int x, int y, int graphic, int frame)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
-    Debug("game:mm:DrawGraphicThruMask_MM", "x = %d,y = %d, graphic = %d",
+    Debug("game:mm:DrawGraphicThruMask_MM", "x = %d, y = %d, graphic = %d",
          x, y, graphic);
     Debug("game:mm:DrawGraphicThruMask_MM", "This should never happen!");
 
@@ -103,14 +112,14 @@ void DrawGraphicThruMask_MM(int x, int y, int graphic)
   }
 #endif
 
-  DrawGraphicThruMaskExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY,
-                           graphic);
+  DrawGraphicThruMaskExt_MM(drawto_mm, cFX + x * TILEX, cFY + y * TILEY,
+                           graphic, frame);
 
-  MarkTileDirty(x,y);
+  MarkTileDirty(x, y);
 }
 
 void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
-                              int graphic)
+                              int graphic, int frame)
 {
   int src_x, src_y;
   Bitmap *src_bitmap;
@@ -118,26 +127,19 @@ void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
   if (graphic == IMG_EMPTY)
     return;
 
-  getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
 
   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
 }
 
 void DrawMiniGraphic_MM(int x, int y, int graphic)
 {
-  DrawMiniGraphicExt_MM(drawto, cSX + x * MINI_TILEX, cSY + y * MINI_TILEY,
+  DrawMiniGraphicExt_MM(drawto_mm, cSX + x * MINI_TILEX, cSY + y * MINI_TILEY,
                        graphic);
 
   MarkTileDirty(x / 2, y / 2);
 }
 
-#if 0
-static void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
-{
-  getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y);
-}
-#endif
-
 void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
 {
   Bitmap *bitmap;
@@ -148,8 +150,8 @@ void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
   BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
 }
 
-void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
-                       int cut_mode, int mask_mode)
+void DrawGraphicShifted_MM(int x, int y, int dx, int dy, int graphic,
+                          int cut_mode, int mask_mode)
 {
   int width = TILEX, height = TILEY;
   int cx = 0, cy = 0;
@@ -163,35 +165,35 @@ void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
     return;
   }
 
-  if (dx || dy)                        // Verschiebung der Grafik?
+  if (dx || dy)                                // Verschiebung der Grafik?
   {
-    if (x < BX1)               // Element kommt von links ins Bild
+    if (x < BX1)                       // Element kommt von links ins Bild
     {
       x = BX1;
       width = dx;
       cx = TILEX - dx;
       dx = 0;
     }
-    else if (x > BX2)          // Element kommt von rechts ins Bild
+    else if (x > BX2)                  // Element kommt von rechts ins Bild
     {
       x = BX2;
       width = -dx;
       dx = TILEX + dx;
     }
-    else if (x==BX1 && dx < 0) // Element verläßt links das Bild
+    else if (x == BX1 && dx < 0)       // Element verläßt links das Bild
     {
       width += dx;
       cx = -dx;
       dx = 0;
     }
-    else if (x==BX2 && dx > 0) // Element verläßt rechts das Bild
+    else if (x == BX2 && dx > 0)       // Element verläßt rechts das Bild
       width -= dx;
-    else if (dx)               // allg. Bewegung in x-Richtung
+    else if (dx)                       // allg. Bewegung in x-Richtung
       MarkTileDirty(x + SIGN(dx), y);
 
-    if (y < BY1)               // Element kommt von oben ins Bild
+    if (y < BY1)                       // Element kommt von oben ins Bild
     {
-      if (cut_mode==CUT_BELOW) // Element oberhalb des Bildes
+      if (cut_mode == CUT_BELOW)       // Element oberhalb des Bildes
        return;
 
       y = BY1;
@@ -199,13 +201,13 @@ void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
       cy = TILEY - dy;
       dy = 0;
     }
-    else if (y > BY2)          // Element kommt von unten ins Bild
+    else if (y > BY2)                  // Element kommt von unten ins Bild
     {
       y = BY2;
       height = -dy;
       dy = TILEY + dy;
     }
-    else if (y==BY1 && dy < 0) // Element verläßt oben das Bild
+    else if (y == BY1 && dy < 0)       // Element verläßt oben das Bild
     {
       height += dy;
       cy = -dy;
@@ -213,19 +215,19 @@ void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
     }
     else if (dy > 0 && cut_mode == CUT_ABOVE)
     {
-      if (y == BY2)            // Element unterhalb des Bildes
+      if (y == BY2)                    // Element unterhalb des Bildes
        return;
 
       height = dy;
       cy = TILEY - dy;
       dy = TILEY;
       MarkTileDirty(x, y + 1);
-    }                          // Element verläßt unten das Bild
+    }                                  // Element verläßt unten das Bild
     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
     {
       height -= dy;
     }
-    else if (dy)               // allg. Bewegung in y-Richtung
+    else if (dy)                       // allg. Bewegung in y-Richtung
     {
       MarkTileDirty(x, y + SIGN(dy));
     }
@@ -240,7 +242,7 @@ void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
   dest_y = cFY + y * TILEY + dy;
 
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
     Debug("game:mm:DrawGraphicShifted_MM", "x = %d, y = %d, graphic = %d",
          x, y, graphic);
@@ -251,19 +253,13 @@ void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
 #endif
 
   if (mask_mode == USE_MASKING)
-    BlitBitmapMasked(src_bitmap, drawto_field,
+    BlitBitmapMasked(src_bitmap, drawto_mm,
                     src_x, src_y, TILEX, TILEY, dest_x, dest_y);
   else
-    BlitBitmap(src_bitmap, drawto_field,
+    BlitBitmap(src_bitmap, drawto_mm,
               src_x, src_y, width, height, dest_x, dest_y);
 
-  MarkTileDirty(x,y);
-}
-
-void DrawGraphicShiftedThruMask_MM(int x,int y, int dx,int dy, int graphic,
-                               int cut_mode)
-{
-  DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, USE_MASKING);
+  MarkTileDirty(x, y);
 }
 
 void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element,
@@ -290,7 +286,7 @@ void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element,
   if (dx || dy)
     DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, mask_mode);
   else if (mask_mode == USE_MASKING)
-    DrawGraphicThruMask_MM(x, y, graphic);
+    DrawGraphicThruMask_MM(x, y, graphic, 0);
   else
     DrawGraphic_MM(x, y, graphic);
 }
@@ -309,38 +305,11 @@ void DrawScreenElementShifted_MM(int x, int y, int dx, int dy, int element,
   DrawScreenElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
 }
 
-void DrawLevelElementShifted_MM(int x, int y, int dx, int dy, int element,
-                            int cut_mode)
-{
-  DrawLevelElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
-}
-
-void DrawScreenElementThruMask_MM(int x, int y, int element)
-{
-  DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
-}
-
-void DrawLevelElementThruMask_MM(int x, int y, int element)
-{
-  DrawLevelElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
-}
-
-void DrawLevelFieldThruMask_MM(int x, int y)
-{
-  DrawLevelElementExt_MM(x, y, 0, 0, Tile[x][y], NO_CUTTING, USE_MASKING);
-}
-
 void DrawScreenElement_MM(int x, int y, int element)
 {
   DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
 }
 
-void DrawLevelElement_MM(int x, int y, int element)
-{
-  if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-    DrawScreenElement_MM(SCREENX(x), SCREENY(y), element);
-}
-
 void DrawScreenField_MM(int x, int y)
 {
   int element = Tile[x][y];
@@ -395,7 +364,24 @@ void DrawScreenField_MM(int x, int y)
 
 void DrawLevelField_MM(int x, int y)
 {
-  DrawScreenField_MM(x, y);
+  if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+    DrawScreenField_MM(SCREENX(x), SCREENY(y));
+  else if (IS_MOVING(x, y))
+  {
+    int newx, newy;
+
+    Moving2Blocked(x, y, &newx, &newy);
+    if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
+      DrawScreenField_MM(SCREENX(newx), SCREENY(newy));
+  }
+  else if (IS_BLOCKED(x, y))
+  {
+    int oldx, oldy;
+
+    Blocked2Moving(x, y, &oldx, &oldy);
+    if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
+      DrawScreenField_MM(SCREENX(oldx), SCREENY(oldy));
+  }
 }
 
 void DrawMiniElement_MM(int x, int y, int element)
@@ -433,7 +419,7 @@ void DrawField_MM(int x, int y)
 
 void DrawLevel_MM(void)
 {
-  int x,y;
+  int x, y;
 
   ClearWindow();
 
@@ -472,10 +458,10 @@ void DrawWallsExt_MM(int x, int y, int element, int draw_mask)
       continue;
 
     if (element & (1 << i))
-      BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
+      BlitBitmap(bitmap, drawto_mm, gx, gy, MINI_TILEX, MINI_TILEY,
                 dest_x, dest_y);
     else
-      ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
+      ClearRectangle(drawto_mm, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
   }
 
   MarkTileDirty(x, y);
@@ -526,7 +512,7 @@ void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask)
       getSizedGraphicSource(graphic, frame, MINI_TILESIZE, &bitmap,
                            &src_x, &src_y);
 
-      BlitBitmap(bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
+      BlitBitmap(bitmap, drawto_mm, src_x, src_y, MINI_TILEX, MINI_TILEY,
                 dst_x, dst_y);
     }
   }
@@ -555,79 +541,18 @@ void DrawElement_MM(int x, int y, int element)
           laser.fuse_x == x &&
           laser.fuse_y == y)
     DrawGraphic_MM(x, y, IMG_MM_FUSE);
+  else if (element == EL_GRAY_BALL_ACTIVE)
+    DrawGraphic_MM(x, y, el_act2gfx(EL_GRAY_BALL, MM_ACTION_ACTIVE));
+  else if (element == EL_GRAY_BALL_OPENING)
+    DrawGraphic_MM(x, y, el_act2gfx(EL_GRAY_BALL, MM_ACTION_OPENING));
+  else if (element == EL_BOMB_ACTIVE)
+    DrawGraphic_MM(x, y, el_act2gfx(EL_BOMB, MM_ACTION_ACTIVE));
+  else if (element == EL_MINE_ACTIVE)
+    DrawGraphic_MM(x, y, el_act2gfx(EL_MINE, MM_ACTION_ACTIVE));
   else
     DrawGraphic_MM(x, y, el2gfx(element));
 }
 
-#if 0
-static void DrawMicroWalls_MM(int x, int y, int element)
-{
-  Bitmap *bitmap;
-  int graphic = el2gfx(WALL_BASE(element));
-  int gx, gy;
-  int i;
-
-  getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
-
-  for (i = 0; i < 4; i++)
-  {
-    int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2);
-    int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2);
-
-    if (element & (1 << i))
-      BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos);
-    else
-      ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY);
-  }
-}
-
-static void DrawMicroElement_MM(int x, int y, int element)
-{
-  Bitmap *bitmap;
-  int graphic = el2gfx(element);
-  int gx, gy;
-
-  if (element == EL_EMPTY)
-    return;
-
-  if (IS_WALL(element))
-  {
-    DrawMicroWalls_MM(x, y, element);
-
-    return;
-  }
-
-  getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
-
-  BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY,
-            MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY);
-}
-
-static void DrawMicroLevelExt_MM(int xpos, int ypos)
-{
-  int x, y;
-
-  ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
-
-  for (x = 0; x < STD_LEV_FIELDX; x++)
-    for (y = 0; y < STD_LEV_FIELDY; y++)
-      DrawMicroElement_MM(x, y, Ur[x][y]);
-
-  redraw_mask |= REDRAW_FIELD;
-}
-#endif
-
-void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y)
-{
-  int x, y;
-
-  for (x = 0; x < size_x; x++)
-    for (y = 0; y < size_y; y++)
-      DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y);
-
-  redraw_mask |= REDRAW_FIELD;
-}
-
 
 // ----------------------------------------------------------------------------
 // XSN
@@ -722,7 +647,7 @@ static int xsn_percent(void)
   int xsn_m3 = xsn_m2 + 10;
   time_t xsn_e0 = time(NULL);
   struct tm *xsn_t0 = localtime(&xsn_e0);
-  struct tm xsn_t1 = { 0,0,0, xsn_m2*3, xsn_m3/3, xsn_t0->tm_year, 0,0,-1 };
+  struct tm xsn_t1 = { 0,0,0, xsn_m2 * 3, xsn_m3 / 3, xsn_t0->tm_year, 0,0,-1 };
   time_t xsn_e1 = mktime(&xsn_t1);
   int xsn_c0 = (25 * xsn_m3) << xsn_m1;
   int xsn_c1 = (xsn_t1.tm_wday - xsn_m1) * !!xsn_t1.tm_wday;
@@ -899,16 +824,11 @@ static void DrawTileCursor_Xsn(int draw_target)
   static boolean started = FALSE;
   static boolean active = FALSE;
   static boolean debug = FALSE;
-  static unsigned int check_delay = 0;
-  static unsigned int start_delay = 0;
-  static unsigned int growth_delay = 0;
-  static unsigned int update_delay = 0;
-  static unsigned int change_delay = 0;
-  static unsigned int check_delay_value = XSN_CHECK_DELAY * 1000;
-  static unsigned int start_delay_value = 0;
-  static unsigned int growth_delay_value = 0;
-  static unsigned int update_delay_value = 0;
-  static unsigned int change_delay_value = 0;
+  static DelayCounter check_delay = { XSN_CHECK_DELAY * 1000 };
+  static DelayCounter start_delay = { 0 };
+  static DelayCounter growth_delay = { 0 };
+  static DelayCounter update_delay = { 0 };
+  static DelayCounter change_delay = { 0 };
   static int percent = 0;
   static int debug_value = 0;
   boolean reinitialize = FALSE;
@@ -918,21 +838,21 @@ static void DrawTileCursor_Xsn(int draw_target)
   if (draw_target != DRAW_TO_SCREEN)
     return;
 
-  if (DelayReached(&check_delay, check_delay_value))
+  if (DelayReached(&check_delay))
   {
     percent = (debug ? debug_value * 100 / XSN_DEBUG_STEPS : xsn_percent());
 
     if (debug)
       setup.debug.xsn_percent = percent;
 
-    if (setup.debug.xsn_mode != AUTO)
+    if (setup.debug.xsn_mode != STATE_AUTO)
       percent = setup.debug.xsn_percent;
 
     setup.debug.xsn_percent = percent;
 
     active = (percent > 0);
 
-    if ((active && !active_last) || setup.debug.xsn_mode != AUTO)
+    if ((active && !active_last) || setup.debug.xsn_mode != STATE_AUTO)
       removeHideSetupEntry(&setup.debug.xsn_mode);
     else if (!active && active_last)
       setHideSetupEntry(&setup.debug.xsn_mode);
@@ -996,7 +916,7 @@ static void DrawTileCursor_Xsn(int draw_target)
 
   if (!active_last)
   {
-    start_delay_value = (debug || setup.debug.xsn_mode == TRUE ? 0 :
+    start_delay.value = (debug || setup.debug.xsn_mode == TRUE ? 0 :
                         (XSN_START_DELAY + XSN_RND(XSN_START_DELAY)) * 1000);
     started = FALSE;
 
@@ -1072,12 +992,12 @@ static void DrawTileCursor_Xsn(int draw_target)
 
   if (!started)
   {
-    if (!DelayReached(&start_delay, start_delay_value))
+    if (!DelayReached(&start_delay))
       return;
 
-    update_delay_value = XSN_UPDATE_DELAY;
-    growth_delay_value = XSN_GROWTH_DELAY * 1000;
-    change_delay_value = XSN_CHANGE_DELAY * 1000;
+    update_delay.value = XSN_UPDATE_DELAY;
+    growth_delay.value = XSN_GROWTH_DELAY * 1000;
+    change_delay.value = XSN_CHANGE_DELAY * 1000;
 
     ResetDelayCounter(&growth_delay);
     ResetDelayCounter(&update_delay);
@@ -1088,24 +1008,24 @@ static void DrawTileCursor_Xsn(int draw_target)
 
   if (xsn.num_items < xsn.max_items)
   {
-    if (DelayReached(&growth_delay, growth_delay_value))
+    if (DelayReached(&growth_delay))
     {
       xsn.num_items += XSN_RND(XSN_GROWTH_RATE * 2);
       xsn.num_items = MIN(xsn.num_items, xsn.max_items);
     }
   }
 
-  if (DelayReached(&update_delay, update_delay_value))
+  if (DelayReached(&update_delay))
   {
     for (i = 0; i < xsn.num_items; i++)
       xsn_update_item(i);
   }
 
-  if (DelayReached(&change_delay, change_delay_value))
+  if (DelayReached(&change_delay))
   {
     xsn_update_change();
 
-    change_delay_value = xsn.change_delay * 1000;
+    change_delay.value = xsn.change_delay * 1000;
   }
 
   int xsn_alpha_dx = (gfx.mouse_y > xsn.area_ysize - xsn.max_height ?
@@ -1137,7 +1057,8 @@ static void DrawTileCursor_Xsn(int draw_target)
   }
 }
 
-void DrawTileCursor_MM(int draw_target, boolean tile_cursor_active)
+void DrawTileCursor_MM(int draw_target, int drawing_stage,
+                      boolean tile_cursor_active)
 {
   if (program.headless)
     return;
@@ -1152,7 +1073,12 @@ void DrawTileCursor_MM(int draw_target, boolean tile_cursor_active)
   int width = tilesize;
   int height = tilesize;
 
-  DrawTileCursor_Xsn(draw_target);
+  if (!drawing_stage)
+  {
+    DrawTileCursor_Xsn(draw_target);
+
+    return;
+  }
 
   if (!tile_cursor.enabled ||
       !tile_cursor.active ||
@@ -1198,31 +1124,11 @@ void DrawTileCursor_MM(int draw_target, boolean tile_cursor_active)
                     dst_x, dst_y);
 }
 
-#if 0
-static int REQ_in_range(int x, int y)
-{
-  if (y > DY + 249 && y < DY + 278)
-  {
-    if (x > DX + 1 && x < DX + 48)
-      return 1;
-    else if (x > DX + 51 && x < DX + 98)
-      return 2;
-  }
-
-  return 0;
-}
-#endif
-
 Pixel ReadPixel(DrawBuffer *bitmap, int x, int y)
 {
   return GetPixel(bitmap, x, y);
 }
 
-void SetRGB(unsigned int pixel,
-           unsigned short red, unsigned short green, unsigned short blue)
-{
-}
-
 int get_base_element(int element)
 {
   if (IS_MIRROR(element))
@@ -1247,6 +1153,10 @@ int get_base_element(int element)
     return EL_DF_MIRROR_START;
   else if (IS_DF_MIRROR_AUTO(element))
     return EL_DF_MIRROR_AUTO_START;
+  else if (IS_DF_MIRROR_FIXED(element))
+    return EL_DF_MIRROR_FIXED_START;
+  else if (IS_DF_SLOPE(element))
+    return EL_DF_SLOPE_START;
   else if (IS_PACMAN(element))
     return EL_PACMAN_START;
   else if (IS_GRID_STEEL(element))
@@ -1290,7 +1200,8 @@ int get_num_elements(int element)
       IS_POLAR(element) ||
       IS_BEAMER(element) ||
       IS_DF_MIRROR(element) ||
-      IS_DF_MIRROR_AUTO(element))
+      IS_DF_MIRROR_AUTO(element) ||
+      IS_DF_MIRROR_FIXED(element))
     return 16;
   else if (IS_GRID_STEEL_FIXED(element) ||
           IS_GRID_WOOD_FIXED(element) ||
@@ -1304,7 +1215,8 @@ int get_num_elements(int element)
           IS_RECEIVER(element) ||
           IS_PACMAN(element) ||
           IS_GRID_STEEL(element) ||
-          IS_GRID_WOOD(element))
+          IS_GRID_WOOD(element) ||
+          IS_DF_SLOPE(element))
     return 4;
   else
     return 1;
@@ -1319,35 +1231,150 @@ int get_rotated_element(int element, int step)
   return base_element + (element_phase + step + num_elements) % num_elements;
 }
 
-static int map_element(int element)
+static boolean has_full_rotation(int element)
+{
+  return (IS_BEAMER(element) ||
+         IS_MCDUFFIN(element) ||
+         IS_LASER(element) ||
+         IS_RECEIVER(element) ||
+         IS_PACMAN(element));
+}
+
+#define MM_FLIP_X                      0
+#define MM_FLIP_Y                      1
+#define MM_FLIP_XY                     2
+
+static int getFlippedTileExt_MM(int element, int mode)
+{
+  if (IS_WALL(element))
+  {
+    int base = WALL_BASE(element);
+    int bits = WALL_BITS(element);
+
+    if (mode == MM_FLIP_X)
+    {
+      bits = ((bits & 1) << 1 |
+             (bits & 2) >> 1 |
+             (bits & 4) << 1 |
+             (bits & 8) >> 1);
+    }
+    else if (mode == MM_FLIP_Y)
+    {
+      bits = ((bits & 1) << 2 |
+             (bits & 2) << 2 |
+             (bits & 4) >> 2 |
+             (bits & 8) >> 2);
+    }
+    else if (mode == MM_FLIP_XY)
+    {
+      bits = ((bits & 1) << 0 |
+             (bits & 2) << 1 |
+             (bits & 4) >> 1 |
+             (bits & 8) >> 0);
+    }
+
+    element = base | bits;
+  }
+  else
+  {
+    int base_element = get_base_element(element);
+    int num_elements = get_num_elements(element);
+    int element_phase = element - base_element;
+
+    if (IS_GRID_STEEL(element) || IS_GRID_WOOD(element))
+    {
+      if ((mode == MM_FLIP_XY && element_phase < 2) ||
+         (mode != MM_FLIP_XY && element_phase > 1))
+       element_phase ^= 1;
+    }
+    else if (IS_DF_SLOPE(element))
+    {
+      element_phase = (mode == MM_FLIP_X  ? 5 - element_phase :
+                      mode == MM_FLIP_Y  ? 3 - element_phase :
+                      mode == MM_FLIP_XY ? 4 - element_phase :
+                      element_phase);
+    }
+    else
+    {
+      int num_elements_flip = num_elements;
+
+      if (has_full_rotation(element))
+      {
+       if (mode == MM_FLIP_X)
+         num_elements_flip = num_elements / 2;
+       else if (mode == MM_FLIP_XY)
+         num_elements_flip = num_elements * 3 / 4;
+      }
+      else
+      {
+       if (mode == MM_FLIP_XY)
+         num_elements_flip = num_elements / 2;
+      }
+
+      element_phase = num_elements_flip - element_phase;
+    }
+
+    element = base_element + (element_phase + num_elements) % num_elements;
+  }
+
+  return element;
+}
+
+int getFlippedTileX_MM(int element)
+{
+  return getFlippedTileExt_MM(element, MM_FLIP_X);
+}
+
+int getFlippedTileY_MM(int element)
+{
+  return getFlippedTileExt_MM(element, MM_FLIP_Y);
+}
+
+int getFlippedTileXY_MM(int element)
+{
+  return getFlippedTileExt_MM(element, MM_FLIP_XY);
+}
+
+int map_wall_from_base_element(int element)
 {
   switch (element)
   {
-    case EL_WALL_STEEL:                return EL_STEEL_WALL;
-    case EL_WALL_WOOD:         return EL_WOODEN_WALL;
-    case EL_WALL_ICE:          return EL_ICE_WALL;
-    case EL_WALL_AMOEBA:       return EL_AMOEBA_WALL;
-    case EL_DF_WALL_STEEL:     return EL_DF_STEEL_WALL;
-    case EL_DF_WALL_WOOD:      return EL_DF_WOODEN_WALL;
+    case EL_WALL_STEEL_BASE:   return EL_WALL_STEEL;
+    case EL_WALL_WOOD_BASE:    return EL_WALL_WOOD;
+    case EL_WALL_ICE_BASE:     return EL_WALL_ICE;
+    case EL_WALL_AMOEBA_BASE:  return EL_WALL_AMOEBA;
+    case EL_DF_WALL_STEEL_BASE:        return EL_DF_WALL_STEEL;
+    case EL_DF_WALL_WOOD_BASE: return EL_DF_WALL_WOOD;
 
     default:                   return element;
   }
 }
 
-int el2gfx(int element)
+int map_wall_to_base_element(int element)
 {
-  element = map_element(element);
-
   switch (element)
   {
-    case EL_LIGHTBALL:
-      return IMG_MM_LIGHTBALL_RED + RND(3);
+    case EL_WALL_STEEL:                return EL_WALL_STEEL_BASE;
+    case EL_WALL_WOOD:         return EL_WALL_WOOD_BASE;
+    case EL_WALL_ICE:          return EL_WALL_ICE_BASE;
+    case EL_WALL_AMOEBA:       return EL_WALL_AMOEBA_BASE;
+    case EL_DF_WALL_STEEL:     return EL_DF_WALL_STEEL_BASE;
+    case EL_DF_WALL_WOOD:      return EL_DF_WALL_WOOD_BASE;
 
-    default:
-      return el2img_mm(element);
+    default:                   return element;
   }
 }
 
+int el2gfx(int element)
+{
+  return el2img_mm(map_wall_from_base_element(element));
+}
+
+int el_act2gfx(int element, int action)
+{
+  return el_act2img_mm(map_wall_from_base_element(element), action);
+}
+
 void RedrawPlayfield_MM(void)
 {
   DrawLevel_MM();
@@ -1356,6 +1383,6 @@ void RedrawPlayfield_MM(void)
 
 void BlitScreenToBitmap_MM(Bitmap *target_bitmap)
 {
-  BlitBitmap(drawto_field, target_bitmap,
+  BlitBitmap(drawto_mm, target_bitmap,
             REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
 }
index 97b48f4341ba42d438aa7fb89acf277904c438a8..28ba5c331eef1df5c9ec52750ffacfe205cffb54 100644 (file)
@@ -50,7 +50,8 @@
 
 
 void SetDrawtoField_MM(int);
-void BackToFront(void);
+void BackToFront_MM(void);
+
 void FadeToFront(void);
 void ClearWindow(void);
 
@@ -63,23 +64,17 @@ void DrawGraphicAnimation_MM(int, int, int, int);
 
 void DrawGraphic_MM(int, int, int);
 void DrawGraphicExt_MM(DrawBuffer *, int, int, int);
-void DrawGraphicThruMask_MM(int, int, int);
-void DrawGraphicThruMaskExt_MM(DrawBuffer *, int, int, int);
+void DrawGraphicThruMask_MM(int, int, int, int);
+void DrawGraphicThruMaskExt_MM(DrawBuffer *, int, int, int, int);
 void DrawMiniGraphic_MM(int, int, int);
 void getMiniGraphicSource(int, Bitmap **, int *, int *);
 void DrawMiniGraphicExt_MM(DrawBuffer *, int, int, int);
 void DrawGraphicShifted_MM(int, int, int, int, int, int, int);
-void DrawGraphicShiftedThruMask_MM(int, int, int, int, int, int);
 void DrawScreenElementExt_MM(int, int, int, int, int, int, int);
 void DrawLevelElementExt_MM(int, int, int, int, int, int, int);
 void DrawScreenElementShifted_MM(int, int, int, int, int, int);
-void DrawLevelElementShifted_MM(int, int, int, int, int, int);
-void DrawScreenElementThruMask_MM(int, int, int);
-void DrawLevelElementThruMask_MM(int, int, int);
-void DrawLevelFieldThruMask_MM(int, int);
 void ErdreichAnbroeckeln(int, int);
 void DrawScreenElement_MM(int, int, int);
-void DrawLevelElement_MM(int, int, int);
 void DrawScreenField_MM(int, int);
 void DrawLevelField_MM(int, int);
 void DrawMiniElement_MM(int, int, int);
@@ -92,9 +87,8 @@ void DrawElement_MM(int, int, int);
 void DrawWallsExt_MM(int, int, int, int);
 void DrawWalls_MM(int, int, int);
 void DrawWallsAnimation_MM(int, int, int, int, int);
-void DrawMiniLevel_MM(int, int, int, int);
 void DrawMicroLevel_MM(int, int, boolean);
-void DrawTileCursor_MM(int, boolean);
+void DrawTileCursor_MM(int, int, boolean);
 
 boolean Request(char *, unsigned int);
 unsigned int OpenDoor(unsigned int);
@@ -104,7 +98,6 @@ unsigned int MoveDoor(unsigned int);
 void DrawSpecialEditorDoor_MM(void);
 void UndrawSpecialEditorDoor(void);
 Pixel ReadPixel(DrawBuffer *, int, int);
-void SetRGB(unsigned int, unsigned short, unsigned short, unsigned short);
 
 void CreateToolButtons(void);
 
@@ -113,6 +106,10 @@ int get_element_phase(int);
 int get_num_elements(int);
 int get_rotated_element(int, int);
 
+int map_wall_from_base_element(int);
+int map_wall_to_base_element(int);
+
 int el2gfx(int);
+int el_act2gfx(int, int);
 
 #endif
index 9865b93053a3ab9467cdc455cf06267317ebb3e9..5d5fc38f14a72fdb5f6724da022fc379a194bad5 100644 (file)
@@ -40,7 +40,7 @@ void DDSpriteBuffer_BltImg(int pX, int pY, int graphic, int sync_frame)
   if (graphic < 0)
     return;
 
-  getGraphicSource_SP(&g, graphic, sync_frame, -1, -1);
+  getGraphicSource_SP(&g, graphic, sync_frame);
 
   Blt(pX, pY, g.bitmap, g.src_x, g.src_y);
 }
index c6d2d6dcfec6fa5c62aecaed377fa71343533ce9..39580a30f6ea5f81dbf22eccef16657f2850ca4c 100644 (file)
@@ -25,7 +25,7 @@ void subMainGameLoop_Init(void)
   RedDiskReleasePhase = 0; // (re-)enable red disk release
 }
 
-void subMainGameLoop_Main(byte action, boolean warp_mode)
+void subMainGameLoop_Main(byte action)
 {
   // ---------------------------------------------------------------------------
   // --------------------- START OF GAME-BUSY LOOP -----------------------------
@@ -66,6 +66,10 @@ void subMainGameLoop_Main(byte action, boolean warp_mode)
   // ---------------------- END OF GAME-BUSY LOOP ------------------------------
   // ---------------------------------------------------------------------------
 
+  // if the game is not won when reaching this point, then it is lost
+  if (!game_sp.level_solved)
+    game_sp.game_over = TRUE;
+
   LeadOutCounter = LeadOutCounter - 1;         // do more lead-out after quit
 
   if (LeadOutCounter != 0)                     // lead-out not ready: more
@@ -73,10 +77,6 @@ void subMainGameLoop_Main(byte action, boolean warp_mode)
 
   // lead-out done: exit now
   // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ---------
-
-  // if the game is not won when reaching this point, then it is lost
-  if (!game_sp.level_solved)
-    game_sp.game_over = TRUE;
 }
 
 void subCalculateScreenScrollPos(void)
index 0dd629fbf5ac5a4e876753b8a4458f28587e50bf..7e7ba1e529d1b7bb1a0107b93fde6755a4025fc3 100644 (file)
@@ -14,7 +14,7 @@ extern int ExitToMenuFlag;
 extern int LeadOutCounter;
 
 void subMainGameLoop_Init(void);
-void subMainGameLoop_Main(byte, boolean);
+void subMainGameLoop_Main(byte);
 void subCalculateScreenScrollPos(void);
 
 #endif // MAINGAMELOOP_H
index 78f3bb370f2dd6e9bbe3d01da985f197444da02e..1d327c50684e1f7a642c46ec2d82687e692a3aac 100644 (file)
@@ -96,6 +96,9 @@ clean:
 depend:
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
+depend-clean:
+       $(RM) .depend
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
diff --git a/src/game_sp/export.h b/src/game_sp/export.h
deleted file mode 100644 (file)
index d8b964f..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-#ifndef GAME_SP_EXPORT_H
-#define GAME_SP_EXPORT_H
-
-// ============================================================================
-// functions and definitions exported from game_sp to main program
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// constant definitions
-// ----------------------------------------------------------------------------
-
-#define SP_MAX_PLAYFIELD_WIDTH         MAX_PLAYFIELD_WIDTH
-#define SP_MAX_PLAYFIELD_HEIGHT                MAX_PLAYFIELD_HEIGHT
-
-#define SP_NUM_LEVELS_PER_PACKAGE      111
-
-#define SP_STD_PLAYFIELD_WIDTH         60
-#define SP_STD_PLAYFIELD_HEIGHT                24
-#define SP_LEVEL_NAME_LEN              23
-#define SP_MAX_SPECIAL_PORTS           10
-
-#define SP_HEADER_SIZE                 96
-#define SP_STD_PLAYFIELD_SIZE          (SP_STD_PLAYFIELD_WIDTH *       \
-                                        SP_STD_PLAYFIELD_HEIGHT)
-#define SP_MAX_PLAYFIELD_SIZE          (SP_MAX_PLAYFIELD_WIDTH *       \
-                                        SP_MAX_PLAYFIELD_HEIGHT)
-#define SP_STD_LEVEL_SIZE              (SP_HEADER_SIZE + SP_STD_PLAYFIELD_SIZE)
-
-#define SP_FRAMES_PER_SECOND           35
-
-// use a much higher value to be able to load ultra-long MPX demo files
-// (like for level collection 78, level 88 ("WAITING FOR GODOT AGAIN"))
-// #define SP_MAX_TAPE_LEN                     500000
-#define SP_MAX_TAPE_LEN                        64010   // (see "spfix63.doc")
-
-
-// sound actions
-
-#define actActive                      0
-#define actImpact                      1
-#define actExploding                   2
-#define actDigging                     3
-#define actSnapping                    4
-#define actCollecting                  5
-#define actPassing                     6
-#define actPushing                     7
-#define actDropping                    8
-
-
-// ----------------------------------------------------------------------------
-// data structure definitions
-// ----------------------------------------------------------------------------
-
-#ifndef HAS_SpecialPortType
-typedef struct
-{
-  short PortLocation; // = 2*(x+(y*60))                // big endian format
-  byte Gravity; // 1 = turn on, anything else (0) = turn off
-  byte FreezeZonks; // 2 = turn on, anything else (0) = turn off  (1=off!)
-  byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off
-  byte UnUsed;
-} SpecialPortType;
-#define HAS_SpecialPortType
-#endif
-
-#ifndef HAS_LevelInfoType
-typedef struct
-{
-  byte UnUsed[4];
-  byte InitialGravity; // 1=on, anything else (0) = off
-  byte Version; // SpeedFixVersion XOR &H20
-  char LevelTitle[23];
-  byte InitialFreezeZonks; // 2=on, anything else (0) = off.  (1=off too!)
-  byte InfotronsNeeded;
-
-  // Number of Infotrons needed. 0 means that Supaplex will count the total
-  // amount of Infotrons in the level, and use the low byte of that number.
-  // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!)
-  byte SpecialPortCount; // Maximum 10 allowed!
-  SpecialPortType SpecialPort[10];
-  byte SpeedByte; // = Speed XOR Highbyte(RandomSeed)
-  byte CheckSumByte; // = CheckSum XOR SpeedByte
-  short DemoRandomSeed;                                // little endian format
-} LevelInfoType;
-#define HAS_LevelInfoType
-#endif
-
-struct GameInfo_SP
-{
-  boolean level_solved;
-  boolean game_over;
-
-  // needed for updating panel
-  int time_played;
-  int infotrons_still_needed;
-  int red_disk_count;
-  int score;
-
-  // needed for engine snapshots
-  char **preceding_buffer;
-  int preceding_buffer_size;
-
-  int scroll_xoffset, scroll_yoffset;
-};
-
-struct DemoInfo_SP
-{
-  boolean is_available;                // structure contains valid demo
-
-  int level_nr;                        // number of corresponding level
-
-  int length;                  // number of demo entries
-  byte data[SP_MAX_TAPE_LEN];  // array of demo entries
-};
-
-struct LevelInfo_SP
-{
-  LevelInfoType header;
-  byte header_raw_bytes[SP_HEADER_SIZE];
-
-  int width, height;
-
-  byte playfield[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT];
-
-  struct DemoInfo_SP demo;
-};
-
-struct GraphicInfo_SP
-{
-  Bitmap *bitmap;
-  int src_x, src_y;
-  int src_offset_x, src_offset_y;
-  int dst_offset_x, dst_offset_y;
-  int width, height;
-
-  Bitmap *crumbled_bitmap;
-  int crumbled_src_x, crumbled_src_y;
-  int crumbled_border_size;
-
-  boolean has_crumbled_graphics;
-  boolean preserve_background;
-
-  int unique_identifier;       // used to identify needed screen updates
-};
-
-struct EngineSnapshotInfo_SP
-{
-  struct GameInfo_SP game_sp;
-
-  int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
-  byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
-  byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
-
-  int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE];
-  byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE];
-  byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
-};
-
-
-// ----------------------------------------------------------------------------
-// exported functions
-// ----------------------------------------------------------------------------
-
-extern struct GameInfo_SP game_sp;
-extern struct LevelInfo_SP native_sp_level;
-extern struct EngineSnapshotInfo_SP engine_snapshot_sp;
-
-void sp_open_all(void);
-void sp_close_all(void);
-
-void InitPrecedingPlayfieldMemory(void);
-void InitGfxBuffers_SP(void);
-
-void InitGameEngine_SP(void);
-void GameActions_SP(byte *, boolean);
-
-unsigned int InitEngineRandom_SP(int);
-
-void setLevelInfoToDefaults_SP(void);
-void copyInternalEngineVars_SP(void);
-boolean LoadNativeLevel_SP(char *, int, boolean);
-void SaveNativeLevel_SP(char *);
-
-int getFieldbufferOffsetX_SP(void);
-int getFieldbufferOffsetY_SP(void);
-
-void BlitScreenToBitmap_SP(Bitmap *);
-void RedrawPlayfield_SP(boolean);
-
-void LoadEngineSnapshotValues_SP(void);
-void SaveEngineSnapshotValues_SP(ListNode **);
-
-int map_key_RND_to_SP(int);
-int map_key_SP_to_RND(int);
-
-int getRedDiskReleaseFlag_SP(void);
-
-#endif // GAME_SP_EXPORT_H
diff --git a/src/game_sp/export_sp.h b/src/game_sp/export_sp.h
new file mode 100644 (file)
index 0000000..06ade6d
--- /dev/null
@@ -0,0 +1,209 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// export_sp.h
+// ============================================================================
+
+#ifndef EXPORT_SP_H
+#define EXPORT_SP_H
+
+// ============================================================================
+// functions and definitions exported from game_sp to main program
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// constant definitions
+// ----------------------------------------------------------------------------
+
+#define SP_MAX_PLAYFIELD_WIDTH         MAX_PLAYFIELD_WIDTH
+#define SP_MAX_PLAYFIELD_HEIGHT                MAX_PLAYFIELD_HEIGHT
+
+#define SP_NUM_LEVELS_PER_PACKAGE      111
+
+#define SP_STD_PLAYFIELD_WIDTH         60
+#define SP_STD_PLAYFIELD_HEIGHT                24
+#define SP_LEVEL_NAME_LEN              23
+#define SP_MAX_SPECIAL_PORTS           10
+
+#define SP_HEADER_SIZE                 96
+#define SP_STD_PLAYFIELD_SIZE          (SP_STD_PLAYFIELD_WIDTH *       \
+                                        SP_STD_PLAYFIELD_HEIGHT)
+#define SP_MAX_PLAYFIELD_SIZE          (SP_MAX_PLAYFIELD_WIDTH *       \
+                                        SP_MAX_PLAYFIELD_HEIGHT)
+#define SP_STD_LEVEL_SIZE              (SP_HEADER_SIZE + SP_STD_PLAYFIELD_SIZE)
+
+#define SP_FRAMES_PER_SECOND           35
+
+// use a much higher value to be able to load ultra-long MPX demo files
+// (like for level collection 78, level 88 ("WAITING FOR GODOT AGAIN"))
+// #define SP_MAX_TAPE_LEN                     500000
+#define SP_MAX_TAPE_LEN                        64010   // (see "spfix63.doc")
+
+
+// sound actions
+
+#define actActive                      0
+#define actImpact                      1
+#define actExploding                   2
+#define actDigging                     3
+#define actSnapping                    4
+#define actCollecting                  5
+#define actPassing                     6
+#define actPushing                     7
+#define actDropping                    8
+
+
+// ----------------------------------------------------------------------------
+// data structure definitions
+// ----------------------------------------------------------------------------
+
+#ifndef HAS_SpecialPortType
+typedef struct
+{
+  short PortLocation; // = 2*(x+(y*60))                // big endian format
+  byte Gravity; // 1 = turn on, anything else (0) = turn off
+  byte FreezeZonks; // 2 = turn on, anything else (0) = turn off  (1=off!)
+  byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off
+  byte UnUsed;
+} SpecialPortType;
+#define HAS_SpecialPortType
+#endif
+
+#ifndef HAS_LevelInfoType
+typedef struct
+{
+  byte UnUsed[4];
+  byte InitialGravity; // 1=on, anything else (0) = off
+  byte Version; // SpeedFixVersion XOR &H20
+  char LevelTitle[23];
+  byte InitialFreezeZonks; // 2=on, anything else (0) = off.  (1=off too!)
+  byte InfotronsNeeded;
+
+  // Number of Infotrons needed. 0 means that Supaplex will count the total
+  // amount of Infotrons in the level, and use the low byte of that number.
+  // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!)
+  byte SpecialPortCount; // Maximum 10 allowed!
+  SpecialPortType SpecialPort[10];
+  byte SpeedByte; // = Speed XOR Highbyte(RandomSeed)
+  byte CheckSumByte; // = CheckSum XOR SpeedByte
+  short DemoRandomSeed;                                // little endian format
+} LevelInfoType;
+#define HAS_LevelInfoType
+#endif
+
+struct GameInfo_SP
+{
+  boolean level_solved;
+  boolean game_over;
+
+  // needed for updating panel
+  int time_played;
+  int infotrons_still_needed;
+  int red_disk_count;
+  int score;
+
+  // needed for engine snapshots
+  char **preceding_buffer;
+  int preceding_buffer_size;
+
+  int scroll_xoffset, scroll_yoffset;
+};
+
+struct DemoInfo_SP
+{
+  boolean is_available;                // structure contains valid demo
+
+  int level_nr;                        // number of corresponding level
+
+  int length;                  // number of demo entries
+  byte data[SP_MAX_TAPE_LEN];  // array of demo entries
+};
+
+struct LevelInfo_SP
+{
+  LevelInfoType header;
+  byte header_raw_bytes[SP_HEADER_SIZE];
+
+  int width, height;
+
+  byte playfield[SP_MAX_PLAYFIELD_WIDTH][SP_MAX_PLAYFIELD_HEIGHT];
+
+  struct DemoInfo_SP demo;
+};
+
+struct GraphicInfo_SP
+{
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int src_offset_x, src_offset_y;
+  int dst_offset_x, dst_offset_y;
+  int width, height;
+
+  Bitmap *crumbled_bitmap;
+  int crumbled_src_x, crumbled_src_y;
+  int crumbled_border_size;
+
+  boolean has_crumbled_graphics;
+  boolean preserve_background;
+
+  int unique_identifier;       // used to identify needed screen updates
+};
+
+struct EngineSnapshotInfo_SP
+{
+  struct GameInfo_SP game_sp;
+
+  int PlayField16[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
+  byte PlayField8[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
+  byte DisPlayField[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
+
+  int AnimationPosTable[SP_MAX_PLAYFIELD_SIZE];
+  byte AnimationSubTable[SP_MAX_PLAYFIELD_SIZE];
+  byte TerminalState[SP_MAX_PLAYFIELD_SIZE + SP_HEADER_SIZE];
+};
+
+
+// ----------------------------------------------------------------------------
+// exported functions
+// ----------------------------------------------------------------------------
+
+extern struct GameInfo_SP game_sp;
+extern struct LevelInfo_SP native_sp_level;
+extern struct EngineSnapshotInfo_SP engine_snapshot_sp;
+
+void sp_open_all(void);
+void sp_close_all(void);
+
+void InitPrecedingPlayfieldMemory(void);
+void InitGfxBuffers_SP(void);
+
+void InitGameEngine_SP(void);
+void GameActions_SP(byte[MAX_PLAYERS]);
+
+unsigned int InitEngineRandom_SP(int);
+
+void setLevelInfoToDefaults_SP(void);
+void copyInternalEngineVars_SP(void);
+boolean LoadNativeLevel_SP(char *, int, boolean);
+boolean SaveNativeLevel_SP(char *);
+
+int getFieldbufferOffsetX_SP(void);
+int getFieldbufferOffsetY_SP(void);
+
+void BlitScreenToBitmap_SP(Bitmap *);
+void RedrawPlayfield_SP(boolean);
+
+void LoadEngineSnapshotValues_SP(void);
+void SaveEngineSnapshotValues_SP(ListNode **);
+
+int map_key_RND_to_SP(int);
+int map_key_SP_to_RND(int);
+
+int getRedDiskReleaseFlag_SP(void);
+
+#endif // EXPORT_SP_H
index a66187c582f5d04f6b13dcbaea72a6d8036eec63..677152ba4f7ae11b8053e2cda8dc8a2d39253a63 100644 (file)
@@ -512,7 +512,7 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos,
   return TRUE;
 }
 
-void SaveNativeLevel_SP(char *filename)
+boolean SaveNativeLevel_SP(char *filename)
 {
   LevelInfoType *header = &native_sp_level.header;
   FILE *file;
@@ -522,7 +522,7 @@ void SaveNativeLevel_SP(char *filename)
   {
     Warn("cannot save native level file '%s'", filename);
 
-    return;
+    return FALSE;
   }
 
   // write level playfield (width * height == 60 * 24 tiles == 1440 bytes)
@@ -573,4 +573,6 @@ void SaveNativeLevel_SP(char *filename)
   }
 
   fclose(file);
+
+  return TRUE;
 }
index 22c657288cd88a0d1c29af2478feba589c5e678e..523f6619b39194608329fe33fbee6c6d72508ad4 100644 (file)
@@ -14,6 +14,7 @@
 
 #define GAME_SP_VERSION_1_0_0
 
-#include "export.h"
+#include "import_sp.h"
+#include "export_sp.h"
 
 #endif // GAME_SP_H
diff --git a/src/game_sp/import_sp.h b/src/game_sp/import_sp.h
new file mode 100644 (file)
index 0000000..1ade833
--- /dev/null
@@ -0,0 +1,36 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// import_sp.h
+// ============================================================================
+
+#ifndef IMPORT_SP_H
+#define IMPORT_SP_H
+
+// ============================================================================
+// functions and definitions imported from main program to game_sp
+// ============================================================================
+
+#include "../libgame/libgame.h"
+#include "../conf_gfx.h"
+#include "../game.h"
+
+#include "export_sp.h"
+
+
+// ----------------------------------------------------------------------------
+// imported functions
+// ----------------------------------------------------------------------------
+
+void CheckSingleStepMode_SP(boolean, boolean);
+
+void getGraphicSource_SP(struct GraphicInfo_SP *, int, int);
+int getGraphicInfo_Delay(int);
+boolean isNextAnimationFrame_SP(int, int);
+
+#endif // IMPORT_SP_H
index 7eed1dd5d44bde6fb11c22abb8b14359d2517156..206ae571c3486a118b19d48d8300dbd85545b04d 100644 (file)
@@ -72,7 +72,7 @@ static void UpdateGameDoorValues_SP(void)
   game_sp.score = 0;           // (currently no score in Supaplex engine)
 }
 
-void GameActions_SP(byte action[MAX_PLAYERS], boolean warp_mode)
+void GameActions_SP(byte action[MAX_PLAYERS])
 {
   byte single_player_action = action[0];
   int x, y;
@@ -80,7 +80,7 @@ void GameActions_SP(byte action[MAX_PLAYERS], boolean warp_mode)
   UpdateEngineValues(mScrollX / TILEX, mScrollY / TILEY,
                     MurphyScreenXPos / TILEX, MurphyScreenYPos / TILEY);
 
-  subMainGameLoop_Main(single_player_action, warp_mode);
+  subMainGameLoop_Main(single_player_action);
 
   RedrawPlayfield_SP(FALSE);
 
index 58693d8db95bbbb00f0a259b1d66605806fa9163..00aa5129fcbaba79313bf62313491c3cabfc99ea 100644 (file)
@@ -1,3 +1,14 @@
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2024 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 https://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// main_sp.h
+// ============================================================================
+
 #ifndef MAIN_SP_H
 #define MAIN_SP_H
 
 // external functions and definitions imported from main program to game_sp
 // ============================================================================
 
-#include "../engines.h"
-#include "../conf_gfx.h"
+#include "import_sp.h"
 
 
 // ============================================================================
 // functions and definitions that are exported from game_sp to main program
 // ============================================================================
 
-#include "export.h"
+#include "export_sp.h"
 
 
 // ============================================================================
index 8c0f26e3ede53fd49e6feccfa6ed995f635d7e54..807a9a14e5d238bc94504f08e80c5b1956a937ae 100644 (file)
 
 
 #define CONFIG_TOKEN_FONT_INITIAL              "font.initial"
+#define CONFIG_TOKEN_GLOBAL_BUSY_INITIAL       "global.busy_initial"
 #define CONFIG_TOKEN_GLOBAL_BUSY               "global.busy"
+#define CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD     "global.busy_playfield"
+#define CONFIG_TOKEN_BACKGROUND                        "background"
+#define CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL        "background.LOADING_INITIAL"
+#define CONFIG_TOKEN_BACKGROUND_LOADING                "background.LOADING"
+
+#define INITIAL_IMG_GLOBAL_BUSY_INITIAL                0
+#define INITIAL_IMG_GLOBAL_BUSY                        1
+#define INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD      2
+
+#define NUM_INITIAL_IMAGES_BUSY                        3
+
+#define INITIAL_IMG_BACKGROUND                 3
+#define INITIAL_IMG_BACKGROUND_LOADING_INITIAL 4
+#define INITIAL_IMG_BACKGROUND_LOADING         5
+
+#define NUM_INITIAL_IMAGES                     6
 
 
 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
-static struct GraphicInfo    anim_initial;
+static struct GraphicInfo   image_initial[NUM_INITIAL_IMAGES];
 
 static int copy_properties[][5] =
 {
@@ -93,38 +110,75 @@ static int copy_properties[][5] =
 static int get_graphic_parameter_value(char *, char *, int);
 
 
-static void DrawInitAnim(void)
+static int getLoadingBackgroundImage(int graphic)
+{
+  return getImageFromGraphicOrDefault(graphic, INITIAL_IMG_BACKGROUND);
+}
+
+static void SetLoadingWindowBackgroundImage(int graphic)
+{
+  SetBackgroundImage(getLoadingBackgroundImage(graphic), REDRAW_ALL);
+}
+
+static void SetLoadingBackgroundImage(void)
 {
   struct GraphicInfo *graphic_info_last = graphic_info;
-  int graphic = 0;
-  static unsigned int action_delay = 0;
-  unsigned int action_delay_value = GameFrameDelay;
+  int background_image = (game_status_last_screen == -1 ?
+                         INITIAL_IMG_BACKGROUND_LOADING_INITIAL :
+                         INITIAL_IMG_BACKGROUND_LOADING);
+
+  graphic_info = image_initial;
+
+  SetDrawDeactivationMask(REDRAW_NONE);
+  SetDrawBackgroundMask(REDRAW_ALL);
+
+  SetLoadingWindowBackgroundImage(background_image);
+
+  graphic_info = graphic_info_last;
+}
+
+static void DrawInitAnim(boolean only_when_loading)
+{
+  struct GraphicInfo *graphic_info_last = graphic_info;
+  int graphic = (game_status_last_screen == -1 ?
+                INITIAL_IMG_GLOBAL_BUSY_INITIAL :
+                game_status == GAME_MODE_LOADING ?
+                INITIAL_IMG_GLOBAL_BUSY :
+                INITIAL_IMG_GLOBAL_BUSY_PLAYFIELD);
+  struct MenuPosInfo *busy = (game_status_last_screen == -1 ?
+                             &init_last.busy_initial :
+                             game_status == GAME_MODE_LOADING ?
+                             &init_last.busy :
+                             &init_last.busy_playfield);
+  static DelayCounter action_delay = { 0 };
   int sync_frame = FrameCounter;
   int x, y;
 
+  action_delay.value = GameFrameDelay;
+
   // prevent OS (Windows) from complaining about program not responding
   CheckQuitEvent();
 
-  if (game_status != GAME_MODE_LOADING)
+  if (game_status != GAME_MODE_LOADING && only_when_loading)
     return;
 
-  if (anim_initial.bitmap == NULL || window == NULL)
+  if (image_initial[graphic].bitmap == NULL || window == NULL)
     return;
 
-  if (!DelayReached(&action_delay, action_delay_value))
+  if (!DelayReached(&action_delay))
     return;
 
-  if (init_last.busy.x == -1)
-    init_last.busy.x = WIN_XSIZE / 2;
-  if (init_last.busy.y == -1)
-    init_last.busy.y = WIN_YSIZE / 2;
+  if (busy->x == -1)
+    busy->x = (game_status == GAME_MODE_LOADING ? WIN_XSIZE / 2 : SXSIZE / 2);
+  if (busy->y == -1)
+    busy->y = (game_status == GAME_MODE_LOADING ? WIN_YSIZE / 2 : SYSIZE / 2);
 
-  x = ALIGNED_TEXT_XPOS(&init_last.busy);
-  y = ALIGNED_TEXT_YPOS(&init_last.busy);
+  x = (game_status == GAME_MODE_LOADING ? 0 : SX) + ALIGNED_TEXT_XPOS(busy);
+  y = (game_status == GAME_MODE_LOADING ? 0 : SY) + ALIGNED_TEXT_YPOS(busy);
 
-  graphic_info = &anim_initial;                // graphic == 0 => anim_initial
+  graphic_info = image_initial;
 
-  if (sync_frame % anim_initial.anim_delay == 0)
+  if (sync_frame % image_initial[graphic].anim_delay == 0)
   {
     Bitmap *src_bitmap;
     int src_x, src_y;
@@ -132,8 +186,12 @@ static void DrawInitAnim(void)
     int height = graphic_info[graphic].height;
     int frame = getGraphicAnimationFrame(graphic, sync_frame);
 
+    ClearRectangleOnBackground(drawto, x, y, width, height);
+
     getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
-    BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
+    BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, width, height, x, y);
+
+    BlitBitmap(drawto, window, x, y, width, height, x, y);
   }
 
   graphic_info = graphic_info_last;
@@ -186,6 +244,10 @@ static void InitElementSmallImagesScaledUp(int graphic)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
 
+  // if graphic was cloned, scale cloned graphic
+  if (graphic_info[graphic].clone_from != -1)
+    graphic = graphic_info[graphic].clone_from;
+
   // create small and game tile sized bitmaps (and scale up, if needed)
   CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
 }
@@ -249,6 +311,10 @@ static void InitScaledImagesScaledUp(int graphic)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
 
+  // if graphic was cloned, scale cloned graphic
+  if (graphic_info[graphic].clone_from != -1)
+    graphic = graphic_info[graphic].clone_from;
+
   ScaleImage(graphic, g->scale_up_factor);
 }
 
@@ -323,7 +389,7 @@ void InitImageTextures(void)
     CreateImageTextures(texture_graphics[i]);
 }
 
-static int getFontBitmapID(int font_nr)
+static int getFontSpecialSuffix(void)
 {
   int special = -1;
 
@@ -336,6 +402,13 @@ static int getFontBitmapID(int font_nr)
   else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
     special = GFX_SPECIAL_ARG_NAMES;
 
+  return special;
+}
+
+static int getFontBitmapID(int font_nr)
+{
+  int special = getFontSpecialSuffix();
+
   if (special != -1)
     return font_info[font_nr].special_bitmap_id[special];
   else
@@ -353,6 +426,22 @@ static int getFontFromToken(char *token)
   return FONT_INITIAL_1;
 }
 
+static char *getTokenFromFont(int font_nr)
+{
+  static char *token = NULL;
+  int special = getFontSpecialSuffix();
+
+  checked_free(token);
+
+  if (special != -1)
+    token = getStringCat2(font_info[font_nr].token_name,
+                          special_suffix_info[special].suffix);
+  else
+    token = getStringCopy(font_info[font_nr].token_name);
+
+  return token;
+}
+
 static void InitFontGraphicInfo(void)
 {
   static struct FontBitmapInfo *font_bitmap_info = NULL;
@@ -364,7 +453,7 @@ static void InitFontGraphicInfo(void)
   if (graphic_info == NULL)            // still at startup phase
   {
     InitFontInfo(font_initial, NUM_INITIAL_FONTS,
-                getFontBitmapID, getFontFromToken);
+                getFontBitmapID, getFontFromToken, getTokenFromFont);
 
     return;
   }
@@ -589,7 +678,7 @@ static void InitFontGraphicInfo(void)
   }
 
   InitFontInfo(font_bitmap_info, num_font_bitmaps,
-              getFontBitmapID, getFontFromToken);
+              getFontBitmapID, getFontFromToken, getTokenFromFont);
 }
 
 static void InitGlobalAnimGraphicInfo(void)
@@ -1066,6 +1155,8 @@ static void InitElementGraphicInfo(void)
       // look for special default action graphic (classic game specific)
       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
        default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
+      if (IS_BDX_ELEMENT(i) && element_info[EL_BDX_DEFAULT].graphic[act] != -1)
+       default_action_graphic = element_info[EL_BDX_DEFAULT].graphic[act];
       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
        default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
@@ -1075,6 +1166,8 @@ static void InitElementGraphicInfo(void)
 
       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
+      if (IS_BDX_ELEMENT(i) && element_info[EL_BDX_DEFAULT].crumbled[act] != -1)
+       default_action_crumbled = element_info[EL_BDX_DEFAULT].crumbled[act];
       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
@@ -1190,6 +1283,19 @@ static void InitElementSpecialGraphicInfo(void)
       action = -1;
     }
 
+    // for BD effect editor graphics, replace element with effect element, if exists
+    if (action != -1 && special == GFX_SPECIAL_ARG_EDITOR)
+    {
+      int element_bd = map_element_RND_to_BD_effect(element, action);
+      int element_ef = map_element_BD_to_RND_cave(element_bd);
+
+      if (element_ef != EL_UNKNOWN)
+      {
+       element = element_ef;
+       action = -1;
+      }
+    }
+
     if (element >= MAX_NUM_ELEMENTS)
       continue;
 
@@ -1256,19 +1362,27 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
   return -1;
 }
 
-static int get_scaled_graphic_width(int graphic)
+static int get_scaled_graphic_width(Bitmap *src_bitmap, int graphic)
 {
   int original_width = getOriginalImageWidthFromImageID(graphic);
   int scale_up_factor = graphic_info[graphic].scale_up_factor;
 
+  // only happens when loaded outside artwork system (like "global.busy")
+  if (graphic_info == image_initial && src_bitmap)
+    original_width = src_bitmap->width;
+
   return original_width * scale_up_factor;
 }
 
-static int get_scaled_graphic_height(int graphic)
+static int get_scaled_graphic_height(Bitmap *src_bitmap, int graphic)
 {
   int original_height = getOriginalImageHeightFromImageID(graphic);
   int scale_up_factor = graphic_info[graphic].scale_up_factor;
 
+  // only happens when loaded outside artwork system (like "global.busy")
+  if (graphic_info == image_initial && src_bitmap)
+    original_height = src_bitmap->height;
+
   return original_height * scale_up_factor;
 }
 
@@ -1323,6 +1437,7 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   g->sort_priority = 0;                        // default for title screens
   g->class = 0;
   g->style = STYLE_DEFAULT;
+  g->alpha = -1;
 
   g->bitmaps = src_bitmaps;
   g->bitmap = src_bitmap;
@@ -1352,8 +1467,8 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (g->use_image_size)
   {
     // set new default bitmap size (with scaling, but without small images)
-    g->width  = get_scaled_graphic_width(graphic);
-    g->height = get_scaled_graphic_height(graphic);
+    g->width  = get_scaled_graphic_width(src_bitmap, graphic);
+    g->height = get_scaled_graphic_height(src_bitmap, graphic);
   }
 
   // optional width and height of each animation frame
@@ -1400,15 +1515,8 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (src_bitmap)
   {
     // get final bitmap size (with scaling, but without small images)
-    int src_image_width  = get_scaled_graphic_width(graphic);
-    int src_image_height = get_scaled_graphic_height(graphic);
-
-    if (src_image_width == 0 || src_image_height == 0)
-    {
-      // only happens when loaded outside artwork system (like "global.busy")
-      src_image_width  = src_bitmap->width;
-      src_image_height = src_bitmap->height;
-    }
+    int src_image_width  = get_scaled_graphic_width(src_bitmap, graphic);
+    int src_image_height = get_scaled_graphic_height(src_bitmap, graphic);
 
     if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
     {
@@ -1467,7 +1575,7 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
 
   // optionally, the second movement tile can be specified as start tile
   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
-    g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
+    g->swap_double_tiles = parameter[GFX_ARG_2ND_SWAP_TILES];
 
   // automatically determine correct number of frames, if not defined
   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
@@ -1503,6 +1611,9 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   // animation synchronized with global frame counter, not move position
   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
 
+  // animation synchronized with global anim frame counter, not move position
+  g->anim_global_anim_sync = parameter[GFX_ARG_GLOBAL_ANIM_SYNC];
+
   // optional element for cloning crumble graphics
   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
@@ -1563,7 +1674,7 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
 
   // use a different default value for global animations and toons
-  if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
+  if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_32) ||
       (graphic >= IMG_TOON_1            && graphic <= IMG_TOON_20))
     g->draw_masked = TRUE;
 
@@ -1601,12 +1712,20 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
     g->class = parameter[GFX_ARG_CLASS];
   if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
     g->style = parameter[GFX_ARG_STYLE];
+  if (parameter[GFX_ARG_ALPHA] != ARG_UNDEFINED_VALUE)
+    g->alpha = parameter[GFX_ARG_ALPHA];
 
   // this is only used for drawing menu buttons and text
   g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
   g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
   g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
   g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
+
+  // this is only used for drawing stacked global animations
+  g->stacked_xfactor = parameter[GFX_ARG_STACKED_XFACTOR];
+  g->stacked_yfactor = parameter[GFX_ARG_STACKED_YFACTOR];
+  g->stacked_xoffset = parameter[GFX_ARG_STACKED_XOFFSET];
+  g->stacked_yoffset = parameter[GFX_ARG_STACKED_YOFFSET];
 }
 
 static void set_graphic_parameters(int graphic)
@@ -1694,6 +1813,8 @@ static void InitGraphicInfo(void)
     IMG_BACKGROUND_REQUEST,
 
     IMG_BACKGROUND,
+    IMG_BACKGROUND_LOADING_INITIAL,
+    IMG_BACKGROUND_LOADING,
     IMG_BACKGROUND_TITLE_INITIAL,
     IMG_BACKGROUND_TITLE,
     IMG_BACKGROUND_MAIN,
@@ -1701,6 +1822,7 @@ static void InitGraphicInfo(void)
     IMG_BACKGROUND_LEVELS,
     IMG_BACKGROUND_LEVELNR,
     IMG_BACKGROUND_SCORES,
+    IMG_BACKGROUND_SCOREINFO,
     IMG_BACKGROUND_EDITOR,
     IMG_BACKGROUND_INFO,
     IMG_BACKGROUND_INFO_ELEMENTS,
@@ -1882,6 +2004,16 @@ static void InitGraphicCompatibilityInfo(void)
        // process all images which default to same image as "global.door"
        if (strEqual(fi->default_filename, fi_global_door->default_filename))
        {
+         // skip all images that are cloned from images that default to same
+         // image as "global.door", but that are redefined to something else
+         if (graphic_info[i].clone_from != -1)
+         {
+           int cloned_graphic = graphic_info[i].clone_from;
+
+           if (getImageListEntryFromImageID(cloned_graphic)->redefined)
+             continue;
+         }
+
 #if 0
          Debug("init:InitGraphicCompatibilityInfo",
                "special treatment needed for token '%s'", fi->token);
@@ -1894,6 +2026,70 @@ static void InitGraphicCompatibilityInfo(void)
     }
   }
 
+  // special compatibility handling for "Snake Bite" graphics set
+  if (strPrefix(leveldir_current->identifier, "snake_bite"))
+  {
+    Bitmap *bitmap = graphic_info[IMG_BACKGROUND_SCORES].bitmap;
+
+    BlitBitmap(bitmap, bitmap, 18,  66, 32, 480, 50,  66);
+    BlitBitmap(bitmap, bitmap, 466, 66, 32, 480, 434, 66);
+
+    ClearRectangle(bitmap, 2,   66, 32, 480);
+    ClearRectangle(bitmap, 514, 66, 32, 480);
+  }
+
+  // special compatibility handling for "Jue" graphics sets (2007 and 2019)
+  boolean supports_score_info = (menu.draw_xoffset[GAME_MODE_SCOREINFO] != 0);
+  if (strPrefix(artwork.gfx_current_identifier, "jue") && !supports_score_info)
+  {
+    int font_title[] =
+    {
+      FONT_TITLE_1,
+      FONT_TITLE_2,
+
+      -1
+    };
+    int font_text[] =
+    {
+      FONT_TEXT_1,
+      FONT_TEXT_2,
+      FONT_TEXT_3,
+      FONT_TEXT_4,
+
+      -1
+    };
+    int mode_old = GAME_MODE_SCORES;
+    int mode_new = GAME_MODE_SCOREINFO;
+    int i, j;
+
+    // adjust title screens on score info page
+    for (i = 0; font_title[i] != -1; i++)
+    {
+      struct FontInfo *fi = &font_info[font_title[i]];
+
+      fi->special_graphic[mode_new]   = fi->special_graphic[mode_old];
+      fi->special_bitmap_id[mode_new] = fi->special_bitmap_id[mode_old];
+    }
+
+    // adjust vertical text and button positions on scores page
+    for (i = 0; font_text[i] != -1; i++)
+    {
+      for (j = 0; j < 2; j++)
+      {
+       boolean jue0 = strEqual(artwork.gfx_current_identifier, "jue0");
+       int font_nr = (j == 0 ? font_text[i] : FONT_ACTIVE(font_text[i]));
+       int font_bitmap_id = font_info[font_nr].special_bitmap_id[mode_old];
+       int font_yoffset = (jue0 ? 10 : 5);
+
+       gfx.font_bitmap_info[font_bitmap_id].draw_yoffset = font_yoffset;
+      }
+    }
+
+    // adjust page offsets on score info page
+    menu.draw_xoffset[mode_new] = menu.draw_xoffset[mode_old];
+    menu.draw_yoffset[mode_new] = menu.draw_yoffset[mode_old];
+  }
+
   InitGraphicCompatibilityInfo_Doors();
 }
 
@@ -1974,6 +2170,8 @@ static void InitElementSoundInfo(void)
       // look for special default action sound (classic game specific)
       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
        default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
+      if (IS_BDX_ELEMENT(i) && element_info[EL_BDX_DEFAULT].sound[act] != -1)
+       default_action_sound = element_info[EL_BDX_DEFAULT].sound[act];
       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
        default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
@@ -2112,6 +2310,11 @@ static void InitSoundInfo(void)
     }
 
     set_sound_parameters(i, sound->parameter);
+
+#if 0
+    Debug("init:InitSoundInfo", "loop mode: %d ['%s']",
+         sound_info[i].loop, sound->token);
+#endif
   }
 
   free(sound_effect_properties);
@@ -2236,6 +2439,13 @@ static void InitMusicInfo(void)
   }
 }
 
+
+static void InitGameInfoFromArtworkInfo(void)
+{
+  // special case: store initial value of custom artwork setting
+  game.use_masked_elements_initial = game.use_masked_elements;
+}
+
 static void ReinitializeGraphics(void)
 {
   print_timestamp_init("ReinitializeGraphics");
@@ -2263,22 +2473,21 @@ static void ReinitializeGraphics(void)
   InitImageTextures();                 // create textures for certain images
   print_timestamp_time("InitImageTextures");
 
+  InitGraphicInfo_BD();                        // graphic mapping for BD engine
+  print_timestamp_time("InitGraphicInfo_BD");
   InitGraphicInfo_EM();                        // graphic mapping for EM engine
   print_timestamp_time("InitGraphicInfo_EM");
 
   InitGraphicCompatibilityInfo();
   print_timestamp_time("InitGraphicCompatibilityInfo");
 
-  SetMainBackgroundImage(IMG_BACKGROUND);
-  print_timestamp_time("SetMainBackgroundImage");
-  SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
-  print_timestamp_time("SetDoorBackgroundImage");
-
   InitGadgets();
   print_timestamp_time("InitGadgets");
   InitDoors();
   print_timestamp_time("InitDoors");
 
+  InitGameInfoFromArtworkInfo();
+
   print_timestamp_done("ReinitializeGraphics");
 }
 
@@ -3000,6 +3209,22 @@ void InitElementPropertiesStatic(void)
   static int ep_walkable_over[] =
   {
     EL_EMPTY_SPACE,
+    EL_EMPTY_SPACE_1,
+    EL_EMPTY_SPACE_2,
+    EL_EMPTY_SPACE_3,
+    EL_EMPTY_SPACE_4,
+    EL_EMPTY_SPACE_5,
+    EL_EMPTY_SPACE_6,
+    EL_EMPTY_SPACE_7,
+    EL_EMPTY_SPACE_8,
+    EL_EMPTY_SPACE_9,
+    EL_EMPTY_SPACE_10,
+    EL_EMPTY_SPACE_11,
+    EL_EMPTY_SPACE_12,
+    EL_EMPTY_SPACE_13,
+    EL_EMPTY_SPACE_14,
+    EL_EMPTY_SPACE_15,
+    EL_EMPTY_SPACE_16,
     EL_SP_EMPTY_SPACE,
     EL_SOKOBAN_FIELD_EMPTY,
     EL_EXIT_OPEN,
@@ -3297,6 +3522,29 @@ void InitElementPropertiesStatic(void)
     -1
   };
 
+  static int ep_empty_space[] =
+  {
+    EL_EMPTY_SPACE,
+    EL_EMPTY_SPACE_1,
+    EL_EMPTY_SPACE_2,
+    EL_EMPTY_SPACE_3,
+    EL_EMPTY_SPACE_4,
+    EL_EMPTY_SPACE_5,
+    EL_EMPTY_SPACE_6,
+    EL_EMPTY_SPACE_7,
+    EL_EMPTY_SPACE_8,
+    EL_EMPTY_SPACE_9,
+    EL_EMPTY_SPACE_10,
+    EL_EMPTY_SPACE_11,
+    EL_EMPTY_SPACE_12,
+    EL_EMPTY_SPACE_13,
+    EL_EMPTY_SPACE_14,
+    EL_EMPTY_SPACE_15,
+    EL_EMPTY_SPACE_16,
+
+    -1
+  };
+
   static int ep_player[] =
   {
     EL_PLAYER_1,
@@ -3396,15 +3644,15 @@ void InitElementPropertiesStatic(void)
     EL_PLAYER_3,
     EL_PLAYER_4,
     EL_BD_FIREFLY,
-    EL_BD_FIREFLY_1,
-    EL_BD_FIREFLY_2,
-    EL_BD_FIREFLY_3,
-    EL_BD_FIREFLY_4,
+    EL_BD_FIREFLY_LEFT,
+    EL_BD_FIREFLY_DOWN,
+    EL_BD_FIREFLY_RIGHT,
+    EL_BD_FIREFLY_UP,
     EL_BD_BUTTERFLY,
-    EL_BD_BUTTERFLY_1,
-    EL_BD_BUTTERFLY_2,
-    EL_BD_BUTTERFLY_3,
-    EL_BD_BUTTERFLY_4,
+    EL_BD_BUTTERFLY_DOWN,
+    EL_BD_BUTTERFLY_LEFT,
+    EL_BD_BUTTERFLY_UP,
+    EL_BD_BUTTERFLY_RIGHT,
     EL_BD_AMOEBA,
     EL_CHAR_QUESTION,
     EL_UNKNOWN,
@@ -4057,8 +4305,20 @@ void InitElementPropertiesStatic(void)
     EL_AMOEBA_DRY,
     EL_AMOEBA_FULL,
     EL_BD_AMOEBA,
+    EL_BDX_AMOEBA_1,
+    EL_BDX_AMOEBA_2,
+    EL_BDX_SLIME,
+    EL_BDX_ACID,
+    EL_BDX_BITER,
+    EL_BDX_BITER_RIGHT,
+    EL_BDX_BITER_UP,
+    EL_BDX_BITER_LEFT,
+    EL_BDX_BITER_DOWN,
+    EL_BDX_BLADDER,
+    EL_BDX_NUT,
     EL_EMC_MAGIC_BALL,
     EL_EMC_ANDROID,
+    EL_MM_GRAY_BALL,
 
     -1
   };
@@ -4099,6 +4359,22 @@ void InitElementPropertiesStatic(void)
   static int ep_inactive[] =
   {
     EL_EMPTY,
+    EL_EMPTY_SPACE_1,
+    EL_EMPTY_SPACE_2,
+    EL_EMPTY_SPACE_3,
+    EL_EMPTY_SPACE_4,
+    EL_EMPTY_SPACE_5,
+    EL_EMPTY_SPACE_6,
+    EL_EMPTY_SPACE_7,
+    EL_EMPTY_SPACE_8,
+    EL_EMPTY_SPACE_9,
+    EL_EMPTY_SPACE_10,
+    EL_EMPTY_SPACE_11,
+    EL_EMPTY_SPACE_12,
+    EL_EMPTY_SPACE_13,
+    EL_EMPTY_SPACE_14,
+    EL_EMPTY_SPACE_15,
+    EL_EMPTY_SPACE_16,
     EL_SAND,
     EL_WALL,
     EL_BD_WALL,
@@ -4335,6 +4611,8 @@ void InitElementPropertiesStatic(void)
   static int ep_editor_cascade_active[] =
   {
     EL_INTERNAL_CASCADE_BD_ACTIVE,
+    EL_INTERNAL_CASCADE_BDX_ACTIVE,
+    EL_INTERNAL_CASCADE_BDX_EFFECTS_ACTIVE,
     EL_INTERNAL_CASCADE_EM_ACTIVE,
     EL_INTERNAL_CASCADE_EMC_ACTIVE,
     EL_INTERNAL_CASCADE_RND_ACTIVE,
@@ -4348,6 +4626,7 @@ void InitElementPropertiesStatic(void)
     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
     EL_INTERNAL_CASCADE_CE_ACTIVE,
     EL_INTERNAL_CASCADE_GE_ACTIVE,
+    EL_INTERNAL_CASCADE_ES_ACTIVE,
     EL_INTERNAL_CASCADE_REF_ACTIVE,
     EL_INTERNAL_CASCADE_USER_ACTIVE,
     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
@@ -4358,6 +4637,8 @@ void InitElementPropertiesStatic(void)
   static int ep_editor_cascade_inactive[] =
   {
     EL_INTERNAL_CASCADE_BD,
+    EL_INTERNAL_CASCADE_BDX,
+    EL_INTERNAL_CASCADE_BDX_EFFECTS,
     EL_INTERNAL_CASCADE_EM,
     EL_INTERNAL_CASCADE_EMC,
     EL_INTERNAL_CASCADE_RND,
@@ -4371,6 +4652,7 @@ void InitElementPropertiesStatic(void)
     EL_INTERNAL_CASCADE_STEEL_CHARS,
     EL_INTERNAL_CASCADE_CE,
     EL_INTERNAL_CASCADE_GE,
+    EL_INTERNAL_CASCADE_ES,
     EL_INTERNAL_CASCADE_REF,
     EL_INTERNAL_CASCADE_USER,
     EL_INTERNAL_CASCADE_DYNAMIC,
@@ -4428,6 +4710,7 @@ void InitElementPropertiesStatic(void)
     { ep_can_explode,                  EP_CAN_EXPLODE                  },
     { ep_gravity_reachable,            EP_GRAVITY_REACHABLE            },
 
+    { ep_empty_space,                  EP_EMPTY_SPACE                  },
     { ep_player,                       EP_PLAYER                       },
     { ep_can_pass_magic_wall,          EP_CAN_PASS_MAGIC_WALL          },
     { ep_can_pass_dc_magic_wall,       EP_CAN_PASS_DC_MAGIC_WALL       },
@@ -4689,7 +4972,7 @@ void InitElementPropertiesEngine(int engine_version)
     // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
     for (j = 0; j < level.num_android_clone_elements; j++)
       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
-                  (i != EL_EMPTY &&
+                  (!IS_EMPTY(i) &&
                    IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
 
     // ---------- CAN_CHANGE --------------------------------------------------
@@ -4789,7 +5072,7 @@ static void InitGlobal(void)
 
     element_info[i].token_name = element_name_info[i].token_name;
     element_info[i].class_name = element_name_info[i].class_name;
-    element_info[i].editor_description= element_name_info[i].editor_description;
+    element_info[i].editor_description = element_name_info[i].editor_description;
   }
 
   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
@@ -4802,6 +5085,9 @@ static void InitGlobal(void)
     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
   }
 
+  // create hash to store URLs for global animations
+  anim_url_hash = newSetupFileHash();
+
   // create hash from image config list
   image_config_hash = newSetupFileHash();
   for (i = 0; image_config[i].token != NULL; i++)
@@ -4809,6 +5095,13 @@ static void InitGlobal(void)
                 image_config[i].token,
                 image_config[i].value);
 
+  // create hash from sound config list
+  sound_config_hash = newSetupFileHash();
+  for (i = 0; sound_config[i].token != NULL; i++)
+    setHashEntry(sound_config_hash,
+                sound_config[i].token,
+                sound_config[i].value);
+
   // create hash from element token list
   element_token_hash = newSetupFileHash();
   for (i = 0; element_name_info[i].token_name != NULL; i++)
@@ -4903,6 +5196,7 @@ static void InitGlobal(void)
   global.autoplay_leveldir = NULL;
   global.patchtapes_leveldir = NULL;
   global.convert_leveldir = NULL;
+  global.dumplevelset_leveldir = NULL;
   global.dumplevel_leveldir = NULL;
   global.dumptape_leveldir = NULL;
   global.create_sketch_images_dir = NULL;
@@ -5014,6 +5308,23 @@ static void Execute_Command(char *command)
 
     exit(0);
   }
+  else if (strPrefix(command, "dump levelset "))
+  {
+    char *filename = &command[14];
+
+    if (fileExists(filename) && isLevelsetFilename_BD(filename))
+    {
+      DumpLevelsetFromFilename_BD(filename);
+
+      exit(0);
+    }
+
+    char *leveldir = getStringCopy(filename);  // read command parameters
+
+    global.dumplevelset_leveldir = leveldir;
+
+    program.headless = TRUE;
+  }
   else if (strPrefix(command, "dump level "))
   {
     char *filename = &command[11];
@@ -5238,6 +5549,12 @@ static void InitSetup(void)
   if (setup.options.verbose)
     options.verbose = TRUE;
 
+  if (setup.options.debug)
+    options.debug = TRUE;
+
+  if (!strEqual(setup.options.debug_mode, ARG_UNDEFINED_STRING))
+    options.debug_mode = getStringCopy(setup.options.debug_mode);
+
   if (setup.debug.show_frames_per_second)
     global.show_frames_per_second = TRUE;
 }
@@ -5245,10 +5562,9 @@ static void InitSetup(void)
 static void InitGameInfo(void)
 {
   game.restart_level = FALSE;
-  game.restart_game_message = NULL;
-
   game.request_active = FALSE;
-  game.request_active_or_moving = FALSE;
+
+  game.use_masked_elements_initial = FALSE;
 }
 
 static void InitPlayerInfo(void)
@@ -5346,10 +5662,15 @@ static void InitArtworkConfig(void)
 
   // dynamically determine list of sound tokens to be ignored
   num_ignore_sound_tokens = num_ignore_generic_tokens;
+  for (i = 0; sound_config_vars[i].token != NULL; i++)
+    num_ignore_sound_tokens++;
   ignore_sound_tokens =
     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
   for (i = 0; i < num_ignore_generic_tokens; i++)
     ignore_sound_tokens[i] = ignore_generic_tokens[i];
+  for (i = 0; i < num_ignore_sound_tokens - num_ignore_generic_tokens; i++)
+    ignore_sound_tokens[num_ignore_generic_tokens + i] =
+      sound_config_vars[i].token;
   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
 
   // dynamically determine list of music tokens to be ignored
@@ -5449,7 +5770,6 @@ void InitGfxBuffers(void)
   }
 
   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
-  ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
 
@@ -5467,17 +5787,35 @@ void InitGfxBuffers(void)
   // required if door size definitions have changed
   InitGraphicCompatibilityInfo_Doors();
 
+  InitGfxBuffers_BD();
   InitGfxBuffers_EM();
   InitGfxBuffers_SP();
+  InitGfxBuffers_MM();
 }
 
 static void InitGfx(void)
 {
   struct GraphicInfo *graphic_info_last = graphic_info;
   char *filename_font_initial = NULL;
-  char *filename_anim_initial = NULL;
+  char *filename_image_initial[NUM_INITIAL_IMAGES] = { NULL };
+  char *image_token[NUM_INITIAL_IMAGES] =
+  {
+    CONFIG_TOKEN_GLOBAL_BUSY_INITIAL,
+    CONFIG_TOKEN_GLOBAL_BUSY,
+    CONFIG_TOKEN_GLOBAL_BUSY_PLAYFIELD,
+    CONFIG_TOKEN_BACKGROUND,
+    CONFIG_TOKEN_BACKGROUND_LOADING_INITIAL,
+    CONFIG_TOKEN_BACKGROUND_LOADING
+  };
+  struct MenuPosInfo *init_busy[NUM_INITIAL_IMAGES_BUSY] =
+  {
+    &init.busy_initial,
+    &init.busy,
+    &init.busy_playfield
+  };
   Bitmap *bitmap_font_initial = NULL;
-  int i, j;
+  int parameter[NUM_INITIAL_IMAGES][NUM_GFX_ARGS];
+  int i, j, k;
 
   // determine settings for initial font (for displaying startup messages)
   for (i = 0; image_config[i].token != NULL; i++)
@@ -5491,7 +5829,9 @@ static void InitGfx(void)
       len_font_token = strlen(font_token);
 
       if (strEqual(image_config[i].token, font_token))
+      {
        filename_font_initial = image_config[i].value;
+      }
       else if (strlen(image_config[i].token) > len_font_token &&
               strncmp(image_config[i].token, font_token, len_font_token) == 0)
       {
@@ -5520,6 +5860,8 @@ static void InitGfx(void)
   InitGfxCustomArtworkInfo();
   InitGfxOtherSettings();
 
+  InitGfxTileSizeInfo(TILESIZE, TILESIZE);
+
   bitmap_font_initial = LoadCustomImage(filename_font_initial);
 
   for (j = 0; j < NUM_INITIAL_FONTS; j++)
@@ -5527,21 +5869,17 @@ static void InitGfx(void)
 
   InitFontGraphicInfo();
 
-  DrawProgramInfo();
-
-  DrawInitTextHead("Loading graphics");
-
-  // initialize settings for busy animation with default values
-  int parameter[NUM_GFX_ARGS];
-  for (i = 0; i < NUM_GFX_ARGS; i++)
-    parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
-                                               image_config_suffix[i].token,
-                                               image_config_suffix[i].type);
+  InitMenuDesignSettings_Static();
 
-  char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
-  int len_anim_token = strlen(anim_token);
+  // initialize settings for initial images with default values
+  for (i = 0; i < NUM_INITIAL_IMAGES; i++)
+    for (j = 0; j < NUM_GFX_ARGS; j++)
+      parameter[i][j] =
+       get_graphic_parameter_value(image_config_suffix[j].value,
+                                   image_config_suffix[j].token,
+                                   image_config_suffix[j].type);
 
-  // read settings for busy animation from default custom artwork config
+  // read settings for initial images from default custom artwork config
   char *gfx_config_filename = getPath3(options.graphics_directory,
                                       GFX_DEFAULT_SUBDIR,
                                       GRAPHICSINFO_FILENAME);
@@ -5552,79 +5890,110 @@ static void InitGfx(void)
 
     if (setup_file_hash)
     {
-      char *filename = getHashEntry(setup_file_hash, anim_token);
-
-      if (filename)
+      for (i = 0; i < NUM_INITIAL_IMAGES; i++)
       {
-       filename_anim_initial = getStringCopy(filename);
+       char *filename = getHashEntry(setup_file_hash, image_token[i]);
 
-       for (j = 0; image_config_suffix[j].token != NULL; j++)
+       if (filename)
        {
-         int type = image_config_suffix[j].type;
-         char *suffix = image_config_suffix[j].token;
-         char *token = getStringCat2(anim_token, suffix);
-         char *value = getHashEntry(setup_file_hash, token);
+         filename_image_initial[i] = getStringCopy(filename);
 
-         checked_free(token);
+         for (j = 0; image_config_suffix[j].token != NULL; j++)
+         {
+           int type = image_config_suffix[j].type;
+           char *suffix = image_config_suffix[j].token;
+           char *token = getStringCat2(image_token[i], suffix);
+           char *value = getHashEntry(setup_file_hash, token);
 
-         if (value)
-           parameter[j] = get_graphic_parameter_value(value, suffix, type);
+           checked_free(token);
+
+           if (value)
+             parameter[i][j] =
+               get_graphic_parameter_value(value, suffix, type);
+         }
        }
       }
 
+      // read values from custom graphics config file
+      InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
+
       freeSetupFileHash(setup_file_hash);
     }
   }
 
-  if (filename_anim_initial == NULL)
+  for (i = 0; i < NUM_INITIAL_IMAGES; i++)
   {
-    // read settings for busy animation from static default artwork config
-    for (i = 0; image_config[i].token != NULL; i++)
+    if (filename_image_initial[i] == NULL)
     {
-      if (strEqual(image_config[i].token, anim_token))
-       filename_anim_initial = getStringCopy(image_config[i].value);
-      else if (strlen(image_config[i].token) > len_anim_token &&
-              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
+      int len_token = strlen(image_token[i]);
+
+      // read settings for initial images from static default artwork config
+      for (j = 0; image_config[j].token != NULL; j++)
       {
-       for (j = 0; image_config_suffix[j].token != NULL; j++)
+       if (strEqual(image_config[j].token, image_token[i]))
        {
-         if (strEqual(&image_config[i].token[len_anim_token],
-                      image_config_suffix[j].token))
-           parameter[j] =
-             get_graphic_parameter_value(image_config[i].value,
-                                         image_config_suffix[j].token,
-                                         image_config_suffix[j].type);
+         filename_image_initial[i] = getStringCopy(image_config[j].value);
+       }
+       else if (strlen(image_config[j].token) > len_token &&
+                strncmp(image_config[j].token, image_token[i], len_token) == 0)
+       {
+         for (k = 0; image_config_suffix[k].token != NULL; k++)
+         {
+           if (strEqual(&image_config[j].token[len_token],
+                        image_config_suffix[k].token))
+             parameter[i][k] =
+               get_graphic_parameter_value(image_config[j].value,
+                                           image_config_suffix[k].token,
+                                           image_config_suffix[k].type);
+         }
        }
       }
     }
   }
 
-  if (filename_anim_initial == NULL)   // should not happen
-    Fail("cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
+  for (i = 0; i < NUM_INITIAL_IMAGES; i++)
+  {
+    if (filename_image_initial[i] == NULL)     // should not happen
+      Fail("cannot get filename for '%s'", image_token[i]);
+
+    image_initial[i].bitmaps =
+      checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
 
-  anim_initial.bitmaps =
-    checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
+    if (!strEqual(filename_image_initial[i], UNDEFINED_FILENAME))
+      image_initial[i].bitmaps[IMG_BITMAP_STANDARD] =
+       LoadCustomImage(filename_image_initial[i]);
 
-  anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
-    LoadCustomImage(filename_anim_initial);
+    checked_free(filename_image_initial[i]);
+  }
 
-  checked_free(filename_anim_initial);
+  for (i = 0; i < NUM_INITIAL_IMAGES; i++)
+    image_initial[i].use_image_size = TRUE;
 
-  graphic_info = &anim_initial;                // graphic == 0 => anim_initial
+  graphic_info = image_initial;                // graphic == 0 => image_initial
 
-  set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
+  for (i = 0; i < NUM_INITIAL_IMAGES; i++)
+    set_graphic_parameters_ext(i, parameter[i], image_initial[i].bitmaps);
 
   graphic_info = graphic_info_last;
 
-  init.busy.width  = anim_initial.width;
-  init.busy.height = anim_initial.height;
+  for (i = 0; i < NUM_INITIAL_IMAGES_BUSY; i++)
+  {
+    // set image size for busy animations
+    init_busy[i]->width  = image_initial[i].width;
+    init_busy[i]->height = image_initial[i].height;
+  }
 
-  InitMenuDesignSettings_Static();
+  SetLoadingBackgroundImage();
+
+  ClearRectangleOnBackground(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+  DrawProgramInfo();
 
   InitGfxDrawBusyAnimFunction(DrawInitAnim);
   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
   InitGfxDrawTileCursorFunction(DrawTileCursor);
+  InitGfxDrawEnvelopeRequestFunction(DrawEnvelopeRequestToScreen);
 
   gfx.fade_border_source_status = global.border_status;
   gfx.fade_border_target_status = global.border_status;
@@ -5644,6 +6013,29 @@ static void InitGfxBackground(void)
   redraw_mask = REDRAW_ALL;
 }
 
+static void InitSnd(void)
+{
+  InitSoundSettings_Static();
+
+  // read settings for initial sounds from default custom artwork config
+  char *snd_config_filename = getPath3(options.sounds_directory,
+                                      SND_DEFAULT_SUBDIR,
+                                      SOUNDSINFO_FILENAME);
+
+  if (fileExists(snd_config_filename))
+  {
+    SetupFileHash *setup_file_hash = loadSetupFileHash(snd_config_filename);
+
+    if (setup_file_hash)
+    {
+      // read values from custom sounds config file
+      InitSoundSettings_FromHash(setup_file_hash, FALSE);
+
+      freeSetupFileHash(setup_file_hash);
+    }
+  }
+}
+
 static void InitLevelInfo(void)
 {
   LoadLevelInfo();                             // global level info
@@ -5732,36 +6124,33 @@ static void InitImages(void)
   print_timestamp_done("InitImages");
 }
 
-static void InitSound(char *identifier)
+static void InitSound(void)
 {
   print_timestamp_init("InitSound");
 
-  if (identifier == NULL)
-    identifier = artwork.snd_current->identifier;
-
   // set artwork path to send it to the sound server process
   setLevelArtworkDir(artwork.snd_first);
 
-  InitReloadCustomSounds(identifier);
+  InitReloadCustomSounds();
   print_timestamp_time("InitReloadCustomSounds");
 
+  LoadSoundSettings();
+  print_timestamp_time("LoadSoundSettings");
+
   ReinitializeSounds();
   print_timestamp_time("ReinitializeSounds");
 
   print_timestamp_done("InitSound");
 }
 
-static void InitMusic(char *identifier)
+static void InitMusic(void)
 {
   print_timestamp_init("InitMusic");
 
-  if (identifier == NULL)
-    identifier = artwork.mus_current->identifier;
-
   // set artwork path to send it to the sound server process
   setLevelArtworkDir(artwork.mus_first);
 
-  InitReloadCustomMusic(identifier);
+  InitReloadCustomMusic();
   print_timestamp_time("InitReloadCustomMusic");
 
   ReinitializeMusic();
@@ -5914,9 +6303,9 @@ static void InitOverrideArtwork(void)
   gfx.override_level_music    = FALSE;
 
   // now check if this level set has definitions for custom elements
-  if (setup.override_level_graphics == AUTO ||
-      setup.override_level_sounds   == AUTO ||
-      setup.override_level_music    == AUTO)
+  if (setup.override_level_graphics == STATE_AUTO ||
+      setup.override_level_sounds   == STATE_AUTO ||
+      setup.override_level_music    == STATE_AUTO)
     redefined_ce_found =
       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
@@ -5929,14 +6318,14 @@ static void InitOverrideArtwork(void)
 
   if (redefined_ce_found)
   {
-    // this level set has CE definitions: change "AUTO" to "FALSE"
+    // this level set has CE definitions: change "MODE_AUTO" to "FALSE"
     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
     gfx.override_level_music    = (setup.override_level_music    == TRUE);
   }
   else
   {
-    // this level set has no CE definitions: change "AUTO" to "TRUE"
+    // this level set has no CE definitions: change "MODE_AUTO" to "TRUE"
     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
     gfx.override_level_music    = (setup.override_level_music    != FALSE);
@@ -5950,12 +6339,12 @@ static void InitOverrideArtwork(void)
 #endif
 }
 
-static char *getNewArtworkIdentifier(int type)
+static char *setNewArtworkIdentifier(int type)
 {
   static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
   static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
-  static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
+  static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
   static boolean initialized[3] = { FALSE, FALSE, FALSE };
   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
@@ -5964,6 +6353,9 @@ static char *getNewArtworkIdentifier(int type)
   // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
+  TreeInfo *custom_artwork_set =
+    getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
+  boolean has_custom_artwork_set = (custom_artwork_set != NULL);
   char *artwork_current_identifier;
   char *artwork_new_identifier = NULL; // default: nothing has changed
 
@@ -5981,9 +6373,9 @@ static char *getNewArtworkIdentifier(int type)
 
   if (setup_override_artwork)
     artwork_current_identifier = setup_artwork_set;
-  else if (leveldir_artwork_set != NULL)
+  else if (has_level_artwork_set)
     artwork_current_identifier = leveldir_artwork_set;
-  else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
+  else if (has_custom_artwork_set)
     artwork_current_identifier = leveldir_identifier;
   else
     artwork_current_identifier = setup_artwork_set;
@@ -5993,11 +6385,11 @@ static char *getNewArtworkIdentifier(int type)
 
   // ---------- reload if level set and also artwork set has changed ----------
   if (last_leveldir_identifier[type] != leveldir_identifier &&
-      (last_has_level_artwork_set[type] || has_level_artwork_set))
+      (last_has_custom_artwork_set[type] || has_custom_artwork_set))
     artwork_new_identifier = artwork_current_identifier;
 
   last_leveldir_identifier[type] = leveldir_identifier;
-  last_has_level_artwork_set[type] = has_level_artwork_set;
+  last_has_custom_artwork_set[type] = has_custom_artwork_set;
 
   // ---------- reload if "override artwork" setting has changed --------------
   if (last_override_level_artwork[type] != setup_override_artwork)
@@ -6012,6 +6404,7 @@ static char *getNewArtworkIdentifier(int type)
   // (we cannot compare string pointers here, so copy string content itself)
   setString(&last_artwork_identifier[type], artwork_current_identifier);
 
+  // ---------- set new artwork identifier ----------
   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
 
   // ---------- do not reload directly after starting -------------------------
@@ -6023,6 +6416,13 @@ static char *getNewArtworkIdentifier(int type)
   return artwork_new_identifier;
 }
 
+static void InitArtworkIdentifier(void)
+{
+  setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+  setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+  setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+}
+
 void ReloadCustomArtwork(int force_reload)
 {
   int last_game_status = game_status;  // save current game status
@@ -6039,9 +6439,9 @@ void ReloadCustomArtwork(int force_reload)
   AdjustGraphicsForEMC();
   AdjustSoundsForEMC();
 
-  gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
-  snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
-  mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+  gfx_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+  snd_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+  mus_new_identifier = setNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
 
   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
                   snd_new_identifier != NULL || force_reload_snd ||
@@ -6056,11 +6456,17 @@ void ReloadCustomArtwork(int force_reload)
 
   FadeOut(REDRAW_ALL);
 
-  ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
-  print_timestamp_time("ClearRectangle");
+  SetLoadingBackgroundImage();
+
+  ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+  print_timestamp_time("ClearRectangleOnBackground");
 
   FadeIn(REDRAW_ALL);
 
+  UPDATE_BUSY_STATE();
+
+  InitMissingFileHash();
+
   if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
@@ -6078,13 +6484,13 @@ void ReloadCustomArtwork(int force_reload)
 
   if (snd_new_identifier != NULL || force_reload_snd)
   {
-    InitSound(snd_new_identifier);
+    InitSound();
     print_timestamp_time("InitSound");
   }
 
   if (mus_new_identifier != NULL || force_reload_mus)
   {
-    InitMusic(mus_new_identifier);
+    InitMusic();
     print_timestamp_time("InitMusic");
   }
 
@@ -6092,8 +6498,6 @@ void ReloadCustomArtwork(int force_reload)
 
   SetGameStatus(last_game_status);     // restore current game status
 
-  init_last = init;                    // switch to new busy animation
-
   FadeOut(REDRAW_ALL);
 
   RedrawGlobalBorder();
@@ -6161,7 +6565,7 @@ void DisplayExitMessage(char *format, va_list ap)
   sy += 3 * font_height;
 
   num_lines_printed =
-    DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
+    DrawTextBuffer(sx, sy, program.log_filename, font_2,
                   line_length, line_length, max_lines,
                   0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
 
@@ -6174,8 +6578,8 @@ void DisplayExitMessage(char *format, va_list ap)
 
   BackToFront();
 
-  // deactivate toons on error message screen
-  setup.toons = FALSE;
+  // deactivate toons and global animations on error message screen
+  setup.global_animations = FALSE;
 
   WaitForEventToContinue();
 }
@@ -6197,6 +6601,9 @@ void OpenAll(void)
 
   InitRND(NEW_RANDOMIZE);
   InitSimpleRandom(NEW_RANDOMIZE);
+  InitBetterRandom(NEW_RANDOMIZE);
+
+  InitMissingFileHash();
 
   print_timestamp_time("[init global stuff]");
 
@@ -6253,6 +6660,7 @@ void OpenAll(void)
   print_timestamp_time("[init element properties stuff]");
 
   InitGfx();
+  InitSnd();
 
   print_timestamp_time("InitGfx");
 
@@ -6265,19 +6673,23 @@ void OpenAll(void)
   InitOverrideArtwork();       // needs to know current level directory
   print_timestamp_time("InitOverrideArtwork");
 
+  InitArtworkIdentifier();     // needs to know current level directory
+  print_timestamp_time("InitArtworkIdentifier");
+
   InitImages();                        // needs to know current level directory
   print_timestamp_time("InitImages");
 
-  InitSound(NULL);             // needs to know current level directory
+  InitSound();                 // needs to know current level directory
   print_timestamp_time("InitSound");
 
-  InitMusic(NULL);             // needs to know current level directory
+  InitMusic();                 // needs to know current level directory
   print_timestamp_time("InitMusic");
 
   InitArtworkDone();
 
   InitGfxBackground();
 
+  bd_open_all();
   em_open_all();
   sp_open_all();
   mm_open_all();
@@ -6297,6 +6709,11 @@ void OpenAll(void)
     ConvertLevels();
     return;
   }
+  else if (global.dumplevelset_leveldir)
+  {
+    DumpLevelset();
+    return;
+  }
   else if (global.dumplevel_leveldir)
   {
     DumpLevels();
@@ -6330,6 +6747,9 @@ void OpenAll(void)
 
   print_timestamp_done("OpenAll");
 
+  if (setup.ask_for_remaining_tapes)
+    setup.ask_for_uploading_tapes = TRUE;
+
   DrawMainMenu();
 
 #if 0
@@ -6351,13 +6771,49 @@ void OpenAll(void)
 #endif
 }
 
+static boolean WaitForApiThreads(void)
+{
+  DelayCounter thread_delay = { 10000 };
+
+  if (program.api_thread_count == 0)
+    return TRUE;
+
+  // deactivate global animations (not accessible in game state "loading")
+  setup.global_animations = FALSE;
+
+  // set game state to "loading" to be able to show busy animation
+  SetGameStatus(GAME_MODE_LOADING);
+
+  ResetDelayCounter(&thread_delay);
+
+  // wait for threads to finish (and fail on timeout)
+  while (program.api_thread_count > 0)
+  {
+    if (DelayReached(&thread_delay))
+    {
+      Error("failed waiting for threads - TIMEOUT");
+
+      return FALSE;
+    }
+
+    UPDATE_BUSY_STATE();
+
+    Delay(20);
+  }
+
+  return TRUE;
+}
+
 void CloseAllAndExit(int exit_value)
 {
+  WaitForApiThreads();
+
   StopSounds();
   FreeAllSounds();
   FreeAllMusic();
   CloseAudio();                // called after freeing sounds (needed for SDL)
 
+  bd_close_all();
   em_close_all();
   sp_close_all();
 
index a69268f75d09613503bdc866f0a2e582330a167c..8c068587f497d6200d8e213a9c976856c372c3d7 100644 (file)
 
 #include "main.h"
 
-#define setMoveIntoAcidProperty(l, e, v)                       \
-       (setBitfieldProperty(&(l)->can_move_into_acid_bits,     \
-                            EP_CAN_MOVE_INTO_ACID, e, v))
-#define getMoveIntoAcidProperty(l, e)                          \
-       (getBitfieldProperty(&(l)->can_move_into_acid_bits,     \
-                            EP_CAN_MOVE_INTO_ACID, e))
-#define setDontCollideWithProperty(l, e, v)                    \
-       (setBitfieldProperty(&(l)->dont_collide_with_bits,      \
-                            EP_DONT_COLLIDE_WITH, e, v))
-#define getDontCollideWithProperty(l, e)                       \
-       (getBitfieldProperty(&(l)->dont_collide_with_bits,      \
-                            EP_DONT_COLLIDE_WITH, e))
+#define setMoveIntoAcidProperty(l, e, v)       \
+       (setBitfieldProperty(&(l)->can_move_into_acid_bits, EP_CAN_MOVE_INTO_ACID, e, v))
+#define getMoveIntoAcidProperty(l, e)          \
+       (getBitfieldProperty(&(l)->can_move_into_acid_bits, EP_CAN_MOVE_INTO_ACID, e))
+#define setDontCollideWithProperty(l, e, v)    \
+       (setBitfieldProperty(&(l)->dont_collide_with_bits,  EP_DONT_COLLIDE_WITH, e, v))
+#define getDontCollideWithProperty(l, e)       \
+       (getBitfieldProperty(&(l)->dont_collide_with_bits,  EP_DONT_COLLIDE_WITH, e))
 
 void setBitfieldProperty(int *, int, int, boolean);
 boolean getBitfieldProperty(int *, int, int);
index 246655f5ddbf029dc45926d453db86cad3db39d6..54e92ed803b44b201d80c1ef6e4ed807bc97cc2f 100644 (file)
@@ -22,6 +22,7 @@ SRCS =        system.c        \
        image.c         \
        random.c        \
        hash.c          \
+       list.c          \
        http.c          \
        base64.c        \
        setup.c         \
@@ -41,6 +42,7 @@ OBJS =        system.o        \
        image.o         \
        random.o        \
        hash.o          \
+       list.o          \
        http.o          \
        base64.o        \
        setup.o         \
@@ -79,6 +81,9 @@ clean:
 depend:
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
+depend-clean:
+       $(RM) .depend
+
 ifeq (.depend,$(wildcard .depend))
 include .depend
 endif
index 485f81bc9e1ce64b4a4f74a566807f605487a2d4..1c3e6aad5a0dadb27354a88ec15e7686e17ad09f 100644 (file)
@@ -50,7 +50,7 @@
 #include "base64.h"
 
 
-const static char *b64encode =
+static const char *b64encode =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 int base64_encoded_size(int unencoded_size)
@@ -103,10 +103,10 @@ void base64_encode(char *encoded_data,
     *ptr++ = '=';
   }
 
-  *ptr++= '\0';
+  *ptr++ = '\0';
 }
 
-const static byte b64decode[] =
+static const byte b64decode[] =
 {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      //   0
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      //  16
index e150a089809ae1f633b3d377a69219b42dd742fa..844f4f4e9c527fe8025cd3a38665298bb9da4a3c 100644 (file)
@@ -38,6 +38,8 @@ static struct GadgetInfo *gadget_list_last_entry = NULL;
 static struct GadgetInfo *last_info_gi = NULL;
 static int next_free_gadget_id = 1;
 static boolean gadget_id_wrapped = FALSE;
+static int gadget_screen_border_right = -1;
+static int gadget_screen_border_bottom = -1;
 
 static void (*PlayGadgetSoundActivating)(void) = NULL;
 static void (*PlayGadgetSoundSelecting)(void) = NULL;
@@ -50,6 +52,30 @@ void InitGadgetsSoundCallback(void (*activating_function)(void),
   PlayGadgetSoundSelecting = selecting_function;
 }
 
+void InitGadgetScreenBorders(int border_right, int border_bottom)
+{
+  gadget_screen_border_right  = border_right;
+  gadget_screen_border_bottom = border_bottom;
+}
+
+static int getGadgetScreenBorderRight(void)
+{
+  if (gadget_screen_border_right < gfx.sx ||
+      gadget_screen_border_right > gfx.sx + gfx.sxsize)
+    return gfx.sx + gfx.sxsize;
+
+  return gadget_screen_border_right;
+}
+
+static int getGadgetScreenBorderBottom(void)
+{
+  if (gadget_screen_border_bottom < gfx.sy ||
+      gadget_screen_border_bottom > gfx.sy + gfx.sysize)
+    return gfx.sy + gfx.sysize;
+
+  return gadget_screen_border_bottom;
+}
+
 static struct GadgetInfo *getGadgetInfoFromGadgetID(int id)
 {
   struct GadgetInfo *gi = gadget_list_first_entry;
@@ -130,6 +156,16 @@ static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my,
       return gi;
   }
 
+  // full text areas may overlap other active gadgets, so check them first
+  for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
+  {
+    if (gi->mapped && gi->active &&
+       gi->type & GD_TYPE_TEXT_AREA && gi->textarea.full_open &&
+       mx >= gi->textarea.full_x && mx < gi->textarea.full_x + gi->width &&
+       my >= gi->textarea.full_y && my < gi->textarea.full_y + gi->height)
+      return gi;
+  }
+
   // check all other gadgets
   for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
   {
@@ -238,6 +274,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
   {
     case GD_TYPE_NORMAL_BUTTON:
     case GD_TYPE_CHECK_BUTTON:
+    case GD_TYPE_CHECK_BUTTON_2:
     case GD_TYPE_RADIO_BUTTON:
 
       BlitBitmapOnBackground(gd->bitmap, drawto,
@@ -281,7 +318,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                               border_x, gi->height, gi->x, gi->y);
 
        // middle part of gadget
-       for (i=0; i < gi->textbutton.size; i++)
+       for (i = 0; i < gi->textbutton.size; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
                                 font_width, gi->height,
                                 gi->x + border_x + i * font_width, gi->y);
@@ -309,15 +346,19 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        char text[MAX_GADGET_TEXTSIZE + 1];
        int font_nr = (pressed ? gi->font_active : gi->font);
        int font_width = getFontWidth(font_nr);
+       int font_height = getFontHeight(font_nr);
+       struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
        int border_x = gi->border.xsize;
        int border_y = gi->border.ysize;
+       int text_x = gi->x + font->draw_xoffset;
+       int text_y = gi->y + font->draw_yoffset;
 
        // left part of gadget
        BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
                               border_x, gi->height, gi->x, gi->y);
 
        // middle part of gadget
-       for (i=0; i < gi->textinput.size + 1; i++)
+       for (i = 0; i < gi->textinput.size + 1; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
                                 font_width, gi->height,
                                 gi->x + border_x + i * font_width, gi->y);
@@ -332,6 +373,15 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        strcpy(text, gi->textinput.value);
        strcat(text, " ");
 
+       // dirty workaround to erase text if input gadget font has draw offset
+       if (font->draw_xoffset != 0 || font->draw_yoffset != 0)
+         for (i = 0; i < gi->textinput.size + 1; i++)
+           BlitBitmapOnBackground(gd->bitmap, drawto,
+                                  gd->x + border_x, gd->y + border_y,
+                                  font_width, font_height,
+                                  text_x + border_x + i * font_width,
+                                  text_y + border_y);
+
        // gadget text value
        DrawTextExt(drawto,
                    gi->x + border_x, gi->y + border_y, text,
@@ -362,70 +412,114 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        int border_x = gi->border.xsize;
        int border_y = gi->border.ysize;
        int gd_height = 2 * border_y + font_height;
+       int x = gi->x;
+       int y = gi->y;
+       int width  = gi->width;
+       int height = gi->height;
+       int xsize = gi->textarea.xsize;
+       int ysize = gi->textarea.ysize;
+
+       if (gi->textarea.cropped)
+       {
+         if (pressed)
+         {
+           x = gi->textarea.full_x;
+           y = gi->textarea.full_y;
+
+           if (!gi->textarea.full_open)
+           {
+             gi->textarea.full_open = TRUE;
+
+             // save background under fully opened text area
+             BlitBitmap(drawto, gfx.field_save_buffer,
+                        gi->textarea.full_x, gi->textarea.full_y,
+                        gi->width, gi->height,
+                        gi->textarea.full_x, gi->textarea.full_y);
+           }
+         }
+         else
+         {
+           width  = gi->textarea.crop_width;
+           height = gi->textarea.crop_height;
+           xsize = gi->textarea.crop_xsize;
+           ysize = gi->textarea.crop_ysize;
+
+           if (gi->textarea.full_open)
+           {
+             gi->textarea.full_open = FALSE;
+
+             // restore background under fully opened text area
+             BlitBitmap(gfx.field_save_buffer, drawto,
+                        gi->textarea.full_x, gi->textarea.full_y,
+                        gi->width, gi->height,
+                        gi->textarea.full_x, gi->textarea.full_y);
+           }
+         }
+       }
 
        // top left part of gadget border
        BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
-                              border_x, border_y, gi->x, gi->y);
+                              border_x, border_y, x, y);
 
        // top middle part of gadget border
-       for (i=0; i < gi->textarea.xsize; i++)
+       for (i = 0; i < xsize; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
                                 font_width, border_y,
-                                gi->x + border_x + i * font_width, gi->y);
+                                x + border_x + i * font_width, y);
 
        // top right part of gadget border
        BlitBitmapOnBackground(gd->bitmap, drawto,
                               gd->x + gi->border.width - border_x, gd->y,
                               border_x, border_y,
-                              gi->x + gi->width - border_x, gi->y);
+                              x + width - border_x, y);
 
        // left and right part of gadget border for each row
-       for (i=0; i < gi->textarea.ysize; i++)
+       for (i = 0; i < ysize; i++)
        {
          BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y,
                                 border_x, font_height,
-                                gi->x, gi->y + border_y + i * font_height);
+                                x, y + border_y + i * font_height);
          BlitBitmapOnBackground(gd->bitmap, drawto,
                                 gd->x + gi->border.width - border_x,
                                 gd->y + border_y,
                                 border_x, font_height,
-                                gi->x + gi->width - border_x,
-                                gi->y + border_y + i * font_height);
+                                x + width - border_x,
+                                y + border_y + i * font_height);
        }
 
        // bottom left part of gadget border
        BlitBitmapOnBackground(gd->bitmap, drawto,
                               gd->x, gd->y + gd_height - border_y,
                               border_x, border_y,
-                              gi->x, gi->y + gi->height - border_y);
+                              x, y + height - border_y);
 
        // bottom middle part of gadget border
-       for (i=0; i < gi->textarea.xsize; i++)
+       for (i = 0; i < xsize; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto,
                                 gd->x + border_x,
                                 gd->y + gd_height - border_y,
                                 font_width, border_y,
-                                gi->x + border_x + i * font_width,
-                                gi->y + gi->height - border_y);
+                                x + border_x + i * font_width,
+                                y + height - border_y);
 
        // bottom right part of gadget border
        BlitBitmapOnBackground(gd->bitmap, drawto,
                               gd->x + gi->border.width - border_x,
                               gd->y + gd_height - border_y,
                               border_x, border_y,
-                              gi->x + gi->width - border_x,
-                              gi->y + gi->height - border_y);
+                              x + width - border_x,
+                              y + height - border_y);
 
        ClearRectangleOnBackground(drawto,
-                                  gi->x + border_x,
-                                  gi->y + border_y,
-                                  gi->width - 2 * border_x,
-                                  gi->height - 2 * border_y);
+                                  x + border_x,
+                                  y + border_y,
+                                  width - 2 * border_x,
+                                  height - 2 * border_y);
 
        // gadget text value
-       DrawTextBuffer(gi->x + border_x, gi->y + border_y, gi->textarea.value,
-                      font_nr, gi->textarea.xsize, -1, gi->textarea.ysize, 0,
-                      BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE);
+       DrawTextArea(x + border_x, y + border_y, gi->textarea.value,
+                    font_nr, xsize, -1, ysize, 0,
+                    BLIT_ON_BACKGROUND, FALSE, FALSE, FALSE);
 
        cursor_letter = gi->textarea.value[gi->textarea.cursor_position];
        cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
@@ -434,8 +528,8 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        // draw cursor, if active
        if (pressed)
          DrawTextExt(drawto,
-                     gi->x + border_x + gi->textarea.cursor_x * font_width,
-                     gi->y + border_y + gi->textarea.cursor_y * font_height,
+                     x + border_x + gi->textarea.cursor_x * font_width,
+                     y + border_y + gi->textarea.cursor_y * font_height,
                      cursor_string,
                      font_nr, BLIT_INVERSE);
       }
@@ -461,7 +555,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                               border_x, gi->height, gi->x, gi->y);
 
        // middle part of gadget
-       for (i=0; i < gi->selectbox.size; i++)
+       for (i = 0; i < gi->selectbox.size; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
                                 font_width, gi->height,
                                 gi->x + border_x + i * font_width, gi->y);
@@ -514,7 +608,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                                 gi->selectbox.x, gi->selectbox.y);
 
          // top middle part of gadget border
-         for (i=0; i < gi->selectbox.size; i++)
+         for (i = 0; i < gi->selectbox.size; i++)
            BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y,
                                   font_width, border_y,
                                   gi->selectbox.x + border_x + i * font_width,
@@ -535,18 +629,18 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                                 gi->selectbox.y);
 
          // left and right part of gadget border for each row
-         for (i=0; i < gi->selectbox.num_values; i++)
+         for (i = 0; i < gi->selectbox.num_values; i++)
          {
            BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y,
                                   border_x, font_height,
                                   gi->selectbox.x,
-                                  gi->selectbox.y + border_y + i*font_height);
+                                  gi->selectbox.y + border_y + i * font_height);
            BlitBitmapOnBackground(gd->bitmap, drawto,
                                   gd->x + gi->border.width - border_x,
                                   gd->y + border_y,
                                   border_x, font_height,
                                   gi->selectbox.x + box_width - border_x,
-                                  gi->selectbox.y + border_y + i*font_height);
+                                  gi->selectbox.y + border_y + i * font_height);
          }
 
          // bottom left part of gadget border
@@ -557,7 +651,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                                 gi->selectbox.y + box_height - border_y);
 
          // bottom middle part of gadget border
-         for (i=0; i < gi->selectbox.size; i++)
+         for (i = 0; i < gi->selectbox.size; i++)
            BlitBitmapOnBackground(gd->bitmap, drawto,
                                   gd->x + border_x,
                                   gd->y + gi->height - border_y,
@@ -588,7 +682,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                                     gi->selectbox.height - 2 * border_y);
 
          // selectbox text values
-         for (i=0; i < gi->selectbox.num_values; i++)
+         for (i = 0; i < gi->selectbox.num_values; i++)
          {
            int mask_mode = BLIT_MASKED;
 
@@ -663,7 +757,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                               xpos, ypos);
 
        // middle part of gadget
-       for (i=0; i < num_steps; i++)
+       for (i = 0; i < num_steps; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto,
                                 gd->x, gd->y + gi->border.ysize,
                                 gi->width, design_body,
@@ -710,7 +804,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                               xpos, ypos);
 
        // middle part of gadget
-       for (i=0; i < num_steps; i++)
+       for (i = 0; i < num_steps; i++)
          BlitBitmapOnBackground(gd->bitmap, drawto,
                                 gd->x + gi->border.xsize, gd->y,
                                 design_body, gi->height,
@@ -828,6 +922,7 @@ static void DrawGadget_OverlayTouchButton(struct GadgetInfo *gi)
   {
     case GD_TYPE_NORMAL_BUTTON:
     case GD_TYPE_CHECK_BUTTON:
+    case GD_TYPE_CHECK_BUTTON_2:
     case GD_TYPE_RADIO_BUTTON:
       SDL_SetTextureAlphaMod(gd->bitmap->texture_masked, alpha);
       SDL_SetTextureBlendMode(gd->bitmap->texture_masked, SDL_BLENDMODE_BLEND);
@@ -879,7 +974,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 {
   int tag = first_tag;
 
-  if (gi == NULL || gi->deactivated)
+  if (gi == NULL)
     return;
 
   while (tag != GDI_END)
@@ -1072,7 +1167,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        break;
 
       case GDI_ALT_DESIGN_UNPRESSED:
-       gi->alt_design[GD_BUTTON_UNPRESSED].bitmap= va_arg(ap, Bitmap *);
+       gi->alt_design[GD_BUTTON_UNPRESSED].bitmap = va_arg(ap, Bitmap *);
        gi->alt_design[GD_BUTTON_UNPRESSED].x = va_arg(ap, int);
        gi->alt_design[GD_BUTTON_UNPRESSED].y = va_arg(ap, int);
        break;
@@ -1260,11 +1355,11 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     int border_xsize = gi->border.xsize;
     int border_ysize = gi->border.ysize;
     int button_size = gi->border.xsize_selectbutton;
-    int bottom_screen_border = gfx.sy + gfx.sysize - font_height;
+    int bottom_screen_border = getGadgetScreenBorderBottom();
     Bitmap *src_bitmap;
     int src_x, src_y;
 
-    gi->width  = 2 * border_xsize + gi->textinput.size*font_width +button_size;
+    gi->width  = 2 * border_xsize + gi->textinput.size * font_width + button_size;
     gi->height = 2 * border_ysize + font_height;
 
     if (gi->selectbox.options == NULL)
@@ -1358,6 +1453,8 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     int font_height = getFontHeight(font_nr);
     int border_xsize = gi->border.xsize;
     int border_ysize = gi->border.ysize;
+    int right_screen_border = getGadgetScreenBorderRight();
+    int bottom_screen_border = getGadgetScreenBorderBottom();
 
     if (gi->width == 0 || gi->height == 0)
     {
@@ -1369,6 +1466,42 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
       gi->textarea.xsize = (gi->width  - 2 * border_xsize) / font_width;
       gi->textarea.ysize = (gi->height - 2 * border_ysize) / font_height;
     }
+
+    gi->textarea.full_x = gi->x;
+    gi->textarea.full_y = gi->y;
+    gi->textarea.crop_width = gi->width;
+    gi->textarea.crop_height = gi->height;
+    gi->textarea.crop_xsize = gi->textarea.xsize;
+    gi->textarea.crop_ysize = gi->textarea.ysize;
+
+    gi->textarea.cropped = FALSE;
+
+    if (gi->x + gi->width > right_screen_border)
+    {
+      gi->textarea.full_x = MAX(0, right_screen_border - gi->width);
+      gi->textarea.crop_width = right_screen_border - gi->x;
+      gi->textarea.crop_xsize =
+       (gi->textarea.crop_width - 2 * border_xsize) / font_width;
+      gi->textarea.crop_width =
+       2 * border_xsize + gi->textarea.crop_xsize * font_width;
+
+      gi->textarea.cropped = TRUE;
+    }
+
+    if (gi->y + gi->height > bottom_screen_border)
+    {
+      gi->textarea.full_y = MAX(0, bottom_screen_border - gi->height);
+      gi->textarea.crop_height = bottom_screen_border - gi->y;
+      gi->textarea.crop_ysize =
+       (gi->textarea.crop_height - 2 * border_ysize) / font_height;
+      gi->textarea.crop_height =
+       2 * border_ysize + gi->textarea.crop_ysize * font_height;
+
+      gi->textarea.cropped = TRUE;
+    }
+
+    // always start with unselected text area (which is potentially cropped)
+    gi->textarea.full_open = FALSE;
   }
 }
 
@@ -1629,8 +1762,7 @@ void ClickOnGadget(struct GadgetInfo *gi, int button)
 
 boolean HandleGadgets(int mx, int my, int button)
 {
-  static unsigned int pressed_delay = 0;
-  static unsigned int pressed_delay_value = GADGET_FRAME_DELAY;
+  static DelayCounter pressed_delay = { GADGET_FRAME_DELAY };
   static int last_button = 0;
   static int last_mx = 0, last_my = 0;
   static int pressed_mx = 0, pressed_my = 0;
@@ -1756,7 +1888,7 @@ boolean HandleGadgets(int mx, int my, int button)
     (button != 0 && last_gi != NULL && new_gi == last_gi);
 
   gadget_pressed_delay_reached =
-    DelayReached(&pressed_delay, pressed_delay_value);
+    DelayReached(&pressed_delay);
 
   gadget_released =            (release_event && last_gi != NULL);
   gadget_released_inside =     (gadget_released && new_gi == last_gi);
@@ -1860,8 +1992,10 @@ boolean HandleGadgets(int mx, int my, int button)
     else if (gi->type & GD_TYPE_TEXT_AREA && button != 0 && !motion_status)
     {
       int old_cursor_position = gi->textarea.cursor_position;
-      int x = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
-      int y = (my - gi->y - gi->border.ysize) / getFontHeight(gi->font);
+      int gadget_x = mx - gi->textarea.full_x - gi->border.xsize;
+      int gadget_y = my - gi->textarea.full_y - gi->border.ysize;
+      int x = gadget_x / getFontWidth(gi->font);
+      int y = gadget_y / getFontHeight(gi->font);
 
       x = (x < 0 ? 0 : x >= gi->textarea.xsize ? gi->textarea.xsize - 1 : x);
       y = (y < 0 ? 0 : y >= gi->textarea.ysize ? gi->textarea.ysize - 1 : y);
@@ -1937,12 +2071,12 @@ boolean HandleGadgets(int mx, int my, int button)
       ResetDelayCounter(&pressed_delay);
 
       // start gadget delay with longer delay after first click on gadget
-      pressed_delay_value = GADGET_FRAME_DELAY_FIRST;
+      pressed_delay.value = GADGET_FRAME_DELAY_FIRST;
     }
     else                       // gadget hold pressed for some time
     {
       // after first repeated gadget click, continue with shorter delay value
-      pressed_delay_value = GADGET_FRAME_DELAY;
+      pressed_delay.value = GADGET_FRAME_DELAY;
     }
 
     if (gi->type & GD_TYPE_SCROLLBAR && !gadget_dragging)
@@ -2159,7 +2293,11 @@ boolean HandleGadgets(int mx, int my, int button)
     boolean deactivate_gadget = TRUE;
     boolean gadget_changed = TRUE;
 
-    if (gi->type & GD_TYPE_SELECTBOX)
+    if (gi->type == GD_TYPE_CHECK_BUTTON_2)
+    {
+      gi->checked = !gi->checked;
+    }
+    else if (gi->type & GD_TYPE_SELECTBOX)
     {
       if (keep_selectbox_open ||
          mouse_released_where_pressed ||
@@ -2317,8 +2455,7 @@ boolean HandleGadgetsKeyInput(Key key)
     int cursor_pos = gi->textinput.cursor_position;
     char letter = getCharFromKey(key);
     boolean legal_letter = (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC ?
-                           letter >= '0' && letter <= '9' :
-                           letter != 0);
+                           (letter >= '0' && letter <= '9') || letter == '-' : letter != 0);
 
     if (legal_letter && text_length < gi->textinput.size)
     {
@@ -2354,6 +2491,18 @@ boolean HandleGadgetsKeyInput(Key key)
       strcpy(text, gi->textinput.value);
       strcpy(&gi->textinput.value[cursor_pos], &text[cursor_pos + 1]);
 
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
+    }
+    else if (key == KSYM_Home && cursor_pos > 0)
+    {
+      gi->textinput.cursor_position = 0;
+
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
+    }
+    else if (key == KSYM_End && cursor_pos < text_length)
+    {
+      gi->textinput.cursor_position = text_length;
+
       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
   }
@@ -2363,6 +2512,7 @@ boolean HandleGadgetsKeyInput(Key key)
     int text_length = strlen(gi->textarea.value);
     int area_ysize = gi->textarea.ysize;
     int cursor_x_pref = gi->textarea.cursor_x_preferred;
+    int cursor_x = gi->textarea.cursor_x;
     int cursor_y = gi->textarea.cursor_y;
     int cursor_pos = gi->textarea.cursor_position;
     char letter = getCharFromKey(key);
@@ -2414,6 +2564,25 @@ boolean HandleGadgetsKeyInput(Key key)
       strcpy(text, gi->textarea.value);
       strcpy(&gi->textarea.value[cursor_pos], &text[cursor_pos + 1]);
 
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
+    }
+    else if (key == KSYM_Home && cursor_x > 0)
+    {
+      setTextAreaCursorPosition(gi, gi->textarea.cursor_position - cursor_x);
+
+      DrawGadget(gi, DG_PRESSED, gi->direct_draw);
+    }
+    else if (key == KSYM_End && cursor_pos < text_length)
+    {
+      int last_cursor_pos = cursor_pos;
+
+      while (gi->textarea.value[cursor_pos] != '\0' &&
+            gi->textarea.value[cursor_pos] != '\n')
+       cursor_pos++;
+
+      setTextAreaCursorPosition(gi, gi->textarea.cursor_position + cursor_pos -
+                               last_cursor_pos);
+
       DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
   }
index aaf4de16d74900811e137310de508c44f735fc9d..6a27f988f7c8f6b3101708ba0abdaf21d5a2475f 100644 (file)
 #define GD_TYPE_NORMAL_BUTTON          (1 << 0)
 #define GD_TYPE_TEXT_BUTTON            (1 << 1)
 #define GD_TYPE_CHECK_BUTTON           (1 << 2)
-#define GD_TYPE_RADIO_BUTTON           (1 << 3)
-#define GD_TYPE_DRAWING_AREA           (1 << 4)
-#define GD_TYPE_TEXT_INPUT_ALPHANUMERIC        (1 << 5)
-#define GD_TYPE_TEXT_INPUT_NUMERIC     (1 << 6)
-#define GD_TYPE_TEXT_AREA              (1 << 7)
-#define GD_TYPE_SELECTBOX              (1 << 8)
-#define GD_TYPE_SCROLLBAR_VERTICAL     (1 << 9)
-#define GD_TYPE_SCROLLBAR_HORIZONTAL   (1 << 10)
+#define GD_TYPE_CHECK_BUTTON_2         (1 << 3)
+#define GD_TYPE_RADIO_BUTTON           (1 << 4)
+#define GD_TYPE_DRAWING_AREA           (1 << 5)
+#define GD_TYPE_TEXT_INPUT_ALPHANUMERIC        (1 << 6)
+#define GD_TYPE_TEXT_INPUT_NUMERIC     (1 << 7)
+#define GD_TYPE_TEXT_AREA              (1 << 8)
+#define GD_TYPE_SELECTBOX              (1 << 9)
+#define GD_TYPE_SCROLLBAR_VERTICAL     (1 << 10)
+#define GD_TYPE_SCROLLBAR_HORIZONTAL   (1 << 11)
 
 #define GD_TYPE_BUTTON                 (GD_TYPE_NORMAL_BUTTON | \
                                         GD_TYPE_TEXT_BUTTON | \
                                         GD_TYPE_CHECK_BUTTON | \
+                                        GD_TYPE_CHECK_BUTTON_2 | \
                                         GD_TYPE_RADIO_BUTTON)
 #define GD_TYPE_SCROLLBAR              (GD_TYPE_SCROLLBAR_VERTICAL | \
                                         GD_TYPE_SCROLLBAR_HORIZONTAL)
@@ -186,6 +188,15 @@ struct GadgetTextArea
   int cursor_x_preferred;              // "preferred" x cursor position
   int size;                            // maximal size of input text
   int xsize, ysize;                    // size of text area (in chars)
+
+  // automatically determined values
+  boolean cropped;                     // text area cropped to fit viewport
+  int full_x, full_y;                  // text area position when not cropped
+  int crop_width, crop_height;         // size of text area when cropped
+  int crop_xsize, crop_ysize;          // size of text area when cropped
+
+  // runtime values
+  boolean full_open;                   // opening state of text area
 };
 
 struct GadgetSelectbox
@@ -274,6 +285,7 @@ struct GadgetInfo
 
 void InitGadgetsSoundCallback(void (*activating_function)(void),
                              void (*selecting_function)(void));
+void InitGadgetScreenBorders(int, int);
 
 struct GadgetInfo *CreateGadget(int, ...);
 void FreeGadget(struct GadgetInfo *);
index c7f4d73939a5668a5e6b3b3c259086401df40015..b3595ad4ce4517f8f4b50ab5a7ee847ae1513422 100644 (file)
 
 /*****************************************************************************/
 struct hashtable *
-create_hashtable(unsigned int minsize, float maxloadfactor,
-                 unsigned int (*hashf) (void*),
-                 int (*eqf) (void*,void*))
+create_hashtable_ext(unsigned int minsize, float maxloadfactor,
+                    unsigned int (*hashf) (void*),
+                    int (*eqf) (void*, void*),
+                     void (*freekfn) (void*),
+                     void (*freevfn) (void*))
 {
   struct hashtable *h;
   unsigned int i, size = 1u;
@@ -70,7 +72,7 @@ create_hashtable(unsigned int minsize, float maxloadfactor,
     return NULL;
   }
 
-  for (i=0; i < size; i++)
+  for (i = 0; i < size; i++)
     h->table[i] = NULL;
 
   h->tablelength  = size;
@@ -78,10 +80,21 @@ create_hashtable(unsigned int minsize, float maxloadfactor,
   h->hashfn       = hashf;
   h->eqfn         = eqf;
   h->loadlimit    = (unsigned int) ((float)size * maxloadfactor);
+  h->freekfn      = freekfn;
+  h->freevfn      = freevfn;
 
   return h;
 }
 
+struct hashtable *
+create_hashtable(unsigned int (*hashf) (void*),
+                 int (*eqf) (void*, void*),
+                 void (*freekfn) (void*),
+                 void (*freevfn) (void*))
+{
+  return create_hashtable_ext(16, 0.75, hashf, eqf, freekfn, freevfn);
+}
+
 /*****************************************************************************/
 static unsigned int
 hash(struct hashtable *h, void *k)
@@ -134,7 +147,7 @@ hashtable_expand(struct hashtable *h)
       while ((e = h->table[i]) != NULL)
       {
        h->table[i] = e->next;
-       index = indexFor(newsize,e->h);
+       index = indexFor(newsize, e->h);
        e->next = newtable[index];
        newtable[index] = e;
       }
@@ -160,7 +173,7 @@ hashtable_expand(struct hashtable *h)
     {
       for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE)
       {
-       index = indexFor(newsize,e->h);
+       index = indexFor(newsize, e->h);
 
        if (index == i)
        {
@@ -216,8 +229,8 @@ hashtable_insert(struct hashtable *h, void *k, void *v)
     return 0;
   }
 
-  e->h = hash(h,k);
-  index = indexFor(h->tablelength,e->h);
+  e->h = hash(h, k);
+  index = indexFor(h->tablelength, e->h);
   e->k = k;
   e->v = v;
   e->next = h->table[index];
@@ -233,8 +246,8 @@ hashtable_change(struct hashtable *h, void *k, void *v)
   struct entry *e;
   unsigned int hashvalue, index;
 
-  hashvalue = hash(h,k);
-  index = indexFor(h->tablelength,hashvalue);
+  hashvalue = hash(h, k);
+  index = indexFor(h->tablelength, hashvalue);
   e = h->table[index];
 
   while (e != NULL)
@@ -242,7 +255,8 @@ hashtable_change(struct hashtable *h, void *k, void *v)
     /* Check hash value to short circuit heavier comparison */
     if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
     {
-      free(e->v);
+      if (h->freevfn != NULL)
+       h->freevfn(e->v);
       e->v = v;
 
       return -1;
@@ -254,6 +268,29 @@ hashtable_change(struct hashtable *h, void *k, void *v)
   return 0;
 }
 
+/*****************************************************************************/
+int /* checks if key exists */
+hashtable_exists(struct hashtable *h, void *k)
+{
+  struct entry *e;
+  unsigned int hashvalue, index;
+
+  hashvalue = hash(h, k);
+  index = indexFor(h->tablelength, hashvalue);
+  e = h->table[index];
+
+  while (e != NULL)
+  {
+    /* Check hash value to short circuit heavier comparison */
+    if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+      return 1;
+
+    e = e->next;
+  }
+
+  return 0;
+}
+
 /*****************************************************************************/
 void * /* returns value associated with key */
 hashtable_search(struct hashtable *h, void *k)
@@ -261,8 +298,8 @@ hashtable_search(struct hashtable *h, void *k)
   struct entry *e;
   unsigned int hashvalue, index;
 
-  hashvalue = hash(h,k);
-  index = indexFor(h->tablelength,hashvalue);
+  hashvalue = hash(h, k);
+  index = indexFor(h->tablelength, hashvalue);
   e = h->table[index];
 
   while (e != NULL)
@@ -287,7 +324,7 @@ hashtable_remove(struct hashtable *h, void *k)
   struct entry *e;
   struct entry **pE;
   void *v;
-  unsigned int index = indexFor(h->tablelength,hash(h,k));
+  unsigned int index = indexFor(h->tablelength, hash(h, k));
 
   pE = &(h->table[index]);
   e = *pE;
@@ -298,8 +335,13 @@ hashtable_remove(struct hashtable *h, void *k)
     {
       *pE = e->next;
       h->entrycount--;
-      v = e->v;
-      free(e->k);
+      v = NULL;
+      if (h->freekfn != NULL)
+       h->freekfn(e->k);
+      if (h->freevfn != NULL)
+       h->freevfn(e->v);
+      else
+       v = e->v;
       free(e);
 
       return v;
@@ -315,7 +357,7 @@ hashtable_remove(struct hashtable *h, void *k)
 /*****************************************************************************/
 /* destroy */
 void
-hashtable_destroy(struct hashtable *h, int free_values)
+hashtable_destroy(struct hashtable *h)
 {
   unsigned int i;
   struct entry *e, *f;
@@ -329,10 +371,10 @@ hashtable_destroy(struct hashtable *h, int free_values)
     {
       f = e;
       e = e->next;
-      free(f->k);
-
-      if (free_values)
-       free(f->v);
+      if (h->freekfn != NULL)
+       h->freekfn(f->k);
+      if (h->freevfn != NULL)
+       h->freevfn(f->v);
 
       free(f);
     }
@@ -342,7 +384,6 @@ hashtable_destroy(struct hashtable *h, int free_values)
   free(h);
 }
 
-
 /*****************************************************************************/
 /* hashtable_iterator    - iterator constructor */
 
@@ -379,21 +420,27 @@ hashtable_iterator(struct hashtable *h)
 }
 
 /*****************************************************************************/
-/* key - return the key of the (key,value) pair at the current position */
+/* key - return the key of the (key, value) pair at the current position */
 
 void *
-hashtable_iterator_key(struct hashtable_itr *i)
+hashtable_iterator_key(struct hashtable_itr *itr)
 {
-  return i->e->k;
+  if (itr == NULL || itr->e == NULL)
+    return NULL;
+
+  return itr->e->k;
 }
 
 /*****************************************************************************/
-/* value - return the value of the (key,value) pair at the current position */
+/* value - return the value of the (key, value) pair at the current position */
 
 void *
-hashtable_iterator_value(struct hashtable_itr *i)
+hashtable_iterator_value(struct hashtable_itr *itr)
 {
-  return i->e->v;
+  if (itr == NULL || itr->e == NULL)
+    return NULL;
+
+  return itr->e->v;
 }
 
 /*****************************************************************************/
@@ -403,7 +450,7 @@ hashtable_iterator_value(struct hashtable_itr *i)
 int
 hashtable_iterator_advance(struct hashtable_itr *itr)
 {
-  unsigned int j,tablelength;
+  unsigned int j, tablelength;
   struct entry **table;
   struct entry *next;
 
@@ -442,3 +489,110 @@ hashtable_iterator_advance(struct hashtable_itr *itr)
 
   return -1;
 }
+
+/*****************************************************************************/
+/* call function for all hashtable entries */
+void
+hashtable_foreach(struct hashtable *h, hashtable_fn fn, void *userdata)
+{
+  if (h == NULL)
+    return;
+
+  if (hashtable_count(h) == 0)
+    return;
+
+  struct hashtable_itr *itr = hashtable_iterator(h);
+
+  do
+  {
+    fn(hashtable_iterator_key(itr), hashtable_iterator_value(itr), userdata);
+  }
+  while (hashtable_iterator_advance(itr));
+
+  free(itr);
+}
+
+/*****************************************************************************/
+/* call function for all hashtable entries and remove them, if function returned 1 */
+unsigned int
+hashtable_foreach_remove(struct hashtable *h, hashtable_remove_fn fn, void *userdata)
+{
+  if (h == NULL)
+    return 0;
+
+  if (hashtable_count(h) == 0)
+    return 0;
+
+  struct hashtable *remove = create_hashtable(h->hashfn, h->eqfn, NULL, NULL);
+  struct hashtable_itr *itr = hashtable_iterator(h);
+
+  do
+  {
+    if (fn(hashtable_iterator_key(itr), hashtable_iterator_value(itr), userdata))
+      hashtable_insert(remove, hashtable_iterator_key(itr), "1");
+  }
+  while (hashtable_iterator_advance(itr));
+
+  free(itr);
+
+  unsigned int num_removed = 0;
+
+  if (hashtable_count(remove) > 0)
+  {
+    struct hashtable_itr *itr_remove = hashtable_iterator(remove);
+
+    do
+    {
+      hashtable_remove(h, hashtable_iterator_key(itr_remove));
+      num_removed++;
+    }
+    while (hashtable_iterator_advance(itr_remove));
+
+    free(itr_remove);
+  }
+
+  hashtable_destroy(remove);
+
+  return num_removed;
+}
+
+/*****************************************************************************/
+/* remove_all hashtable entries */
+unsigned int
+hashtable_remove_all(struct hashtable *h)
+{
+  /* TODO: this function should directly remove all hashtable entries */
+
+  if (h == NULL)
+    return 0;
+
+  if (hashtable_count(h) == 0)
+    return 0;
+
+  struct hashtable *remove = create_hashtable(h->hashfn, h->eqfn, NULL, NULL);
+  struct hashtable_itr *itr = hashtable_iterator(h);
+
+  do
+  {
+    hashtable_insert(remove, hashtable_iterator_key(itr), "1");
+  }
+  while (hashtable_iterator_advance(itr));
+
+  free(itr);
+
+  struct hashtable_itr *itr_remove = hashtable_iterator(remove);
+  unsigned int num_removed = 0;
+
+  do
+  {
+    hashtable_remove(h, hashtable_iterator_key(itr_remove));
+    num_removed++;
+  }
+  while (hashtable_iterator_advance(itr_remove));
+
+  free(itr_remove);
+
+  hashtable_destroy(remove);
+
+  return num_removed;
+}
index 004d9c581183c5a5537583c37150eb6d673d3fa1..61bc917a6cd45c35d7d4efc0db996db3d7005804 100644 (file)
@@ -45,7 +45,7 @@
  *      static unsigned int         hash_from_key_fn( void *k );
  *      static int                  keys_equal_fn ( void *key1, void *key2 );
  *
- *      h = create_hashtable(16, 0.75, hash_from_key_fn, keys_equal_fn);
+ *      h = create_hashtable(16, 0.75, hash_from_key_fn, keys_equal_fn, free, free);
  *      k = (struct some_key *)     malloc(sizeof(struct some_key));
  *      v = (struct some_value *)   malloc(sizeof(struct some_value));
  *
@@ -109,6 +109,8 @@ struct hashtable
   unsigned int loadlimit;
   unsigned int (*hashfn) (void *k);
   int (*eqfn) (void *k1, void *k2);
+  void (*freekfn) (void *k);
+  void (*freevfn) (void *v);
 };
 
 /*****************************************************************************/
@@ -119,30 +121,43 @@ struct hashtable_itr
   unsigned int index;
 };
 
+typedef struct hashtable HashTable;
+
 
 /*****************************************************************************
- * create_hashtable
+ * create_hashtable_ext
    
  * @name                    create_hashtable
  * @param   minsize         minimum initial size of hashtable
  * @param   maxloadfactor   maximum ratio entries / tablesize
  * @param   hashfunction    function for hashing keys
  * @param   key_eq_fn       function for determining key equality
+ * @param   key_free_fn     function for freeing keys
+ * @param   value_free_fn   function for freeing values
  * @return                  newly created hashtable or NULL on failure
  */
 
 struct hashtable *
-create_hashtable(unsigned int minsize, float maxloadfactor,
-                 unsigned int (*hashfunction) (void*),
-                 int (*key_eq_fn) (void*,void*));
+create_hashtable_ext(unsigned int minsize, float maxloadfactor,
+                     unsigned int (*hashfunction) (void*),
+                     int (*key_eq_fn) (void*, void*),
+                     void (*key_free_fn) (void*),
+                     void (*value_free_fn) (void*));
+
+/* wrapper function using reasonable default values for some parameters */
+struct hashtable *
+create_hashtable(unsigned int (*hashfunction) (void*),
+                 int (*key_eq_fn) (void*, void*),
+                 void (*key_free_fn) (void*),
+                 void (*value_free_fn) (void*));
 
 /*****************************************************************************
  * hashtable_insert
    
  * @name        hashtable_insert
  * @param   h   the hashtable to insert into
- * @param   k   the key - hashtable claims ownership and will free on removal
- * @param   v   the value - does not claim ownership
+ * @param   k   the key   - will be freed on removal if free function defined
+ * @param   v   the value - will be freed on removal if free function defined
  * @return      non-zero for successful insertion
  *
  * This function will cause the table to expand if the insertion would take
@@ -161,7 +176,7 @@ hashtable_insert(struct hashtable *h, void *k, void *v);
 #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
 static int fnname (struct hashtable *h, keytype *k, valuetype *v) \
 { \
-  return hashtable_insert(h,k,v); \
+  return hashtable_insert(h, k, v); \
 }
 
 /*****************************************************************************
@@ -180,7 +195,25 @@ hashtable_change(struct hashtable *h, void *k, void *v);
 #define DEFINE_HASHTABLE_CHANGE(fnname, keytype, valuetype) \
 static int fnname (struct hashtable *h, keytype *k, valuetype *v) \
 { \
-  return hashtable_change(h,k,v); \
+  return hashtable_change(h, k, v); \
+}
+
+/*****************************************************************************
+ * hashtable_exists
+   
+ * @name        hashtable_exists
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for
+ * @return      non-zero if key exists, else zero
+ */
+
+int
+hashtable_exists(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_EXISTS(fnname, keytype, valuetype) \
+static int fnname (struct hashtable *h, keytype *k) \
+{ \
+  return hashtable_exists(h, k); \
 }
 
 /*****************************************************************************
@@ -188,7 +221,7 @@ static int fnname (struct hashtable *h, keytype *k, valuetype *v) \
    
  * @name        hashtable_search
  * @param   h   the hashtable to search
- * @param   k   the key to search for  - does not claim ownership
+ * @param   k   the key to search for
  * @return      the value associated with the key, or NULL if none found
  */
 
@@ -198,7 +231,7 @@ hashtable_search(struct hashtable *h, void *k);
 #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
 static valuetype * fnname (struct hashtable *h, keytype *k) \
 { \
-  return (valuetype *) (hashtable_search(h,k)); \
+  return (valuetype *) (hashtable_search(h, k)); \
 }
 
 /*****************************************************************************
@@ -206,7 +239,7 @@ static valuetype * fnname (struct hashtable *h, keytype *k) \
    
  * @name        hashtable_remove
  * @param   h   the hashtable to remove the item from
- * @param   k   the key to search for  - does not claim ownership
+ * @param   k   the key to search for
  * @return      the value associated with the key, or NULL if none found
  */
 
@@ -216,7 +249,7 @@ hashtable_remove(struct hashtable *h, void *k);
 #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
 static valuetype * fnname (struct hashtable *h, keytype *k) \
 { \
-  return (valuetype *) (hashtable_remove(h,k)); \
+  return (valuetype *) (hashtable_remove(h, k)); \
 }
 
 
@@ -234,11 +267,10 @@ hashtable_count(struct hashtable *h);
  * hashtable_destroy
    
  * @name        hashtable_destroy
- * @param       free_values     whether to call 'free' on the remaining values
  */
 
 void
-hashtable_destroy(struct hashtable *h, int free_values);
+hashtable_destroy(struct hashtable *h);
 
 
 /*****************************************************************************/
@@ -249,13 +281,13 @@ struct hashtable_itr *
 hashtable_iterator(struct hashtable *h);
 
 /*****************************************************************************/
-/* key - return the key of the (key,value) pair at the current position */
+/* key - return the key of the (key, value) pair at the current position */
 
 void *
 hashtable_iterator_key(struct hashtable_itr *i);
 
 /*****************************************************************************/
-/* value - return the value of the (key,value) pair at the current position */
+/* value - return the value of the (key, value) pair at the current position */
 
 void *
 hashtable_iterator_value(struct hashtable_itr *i);
@@ -267,4 +299,64 @@ hashtable_iterator_value(struct hashtable_itr *i);
 int
 hashtable_iterator_advance(struct hashtable_itr *itr);
 
+
+/*****************************************************************************/
+/* hashtable_fn - prototype of function to call for hashtable entry
+
+ * @name        hashtable_fn
+ * @param   k   the key of the current hash entry
+ * @param   v   the value of the current hash entry
+ * @param   u   additional user data
+ */
+
+typedef void (*hashtable_fn) (void *k, void *v, void *u);
+
+/*****************************************************************************/
+/* hashtable_foreach - call function for all hashtable entries
+
+ * @name        hashtable_foreach
+ * @param   h   the hashtable to iterate through
+ * @param   fn  the function to call for each entry
+ */
+
+void
+hashtable_foreach(struct hashtable *h, hashtable_fn fn, void *userdata);
+
+/*****************************************************************************/
+/* hashtable_remove_fn - prototype of function to call for hashtable entry
+
+ * @name        hashtable_remove_fn
+ * @param   k   the key of the current hash entry
+ * @param   v   the value of the current hash entry
+ * @param   u   additional user data
+ * @return      non-zero if entry should be removed, else zero
+ */
+
+typedef int (*hashtable_remove_fn) (void *k, void *v, void *u);
+
+/*****************************************************************************/
+/* hashtable_foreach_remove - call function for all hashtable entries and remove them,
+ *                            if function returned 1
+ *                            returns the number of removed entries
+
+ * @name        hashtable_foreach_remove
+ * @param   h   the hashtable to iterate through
+ * @param   fn  the function to call for each entry
+ * @return      the number of removed entries
+ */
+
+unsigned int
+hashtable_foreach_remove(struct hashtable *h, hashtable_remove_fn fn, void *userdata);
+
+/*****************************************************************************/
+/* hashtable_remove_all - remove_all hashtable entries
+
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove all entries from
+ * @return      the number of removed entries
+ */
+
+unsigned int
+hashtable_remove_all(struct hashtable *h);
+
 #endif
index cfab11fc0dd7a872bf3169ea75d9c4bc4a92393c..c83c91f71b1515695da8540a0f7c384b9c4f74ea 100644 (file)
@@ -65,18 +65,18 @@ static void SetHttpResponseToDefaults(struct HttpResponse *response)
   response->status_text[0] = '\0';
 }
 
-struct HttpResponse *GetHttpResponseFromBuffer(void *buffer, int size)
+struct HttpResponse *GetHttpResponseFromBuffer(void *buffer, int body_size)
 {
-  if (size > MAX_HTTP_BODY_SIZE)
+  if (body_size > MAX_HTTP_BODY_SIZE)
     return NULL;
 
   struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
 
   SetHttpResponseToDefaults(response);
 
-  strncpy(response->body, buffer, MAX_HTTP_BODY_SIZE);
-  response->body[MAX_HTTP_BODY_SIZE] = '\0';
-  response->body_size = MIN(size, MAX_HTTP_BODY_SIZE);
+  memcpy(response->body, buffer, body_size);
+  response->body[body_size] = '\0';
+  response->body_size = body_size;
 
   return response;
 }
@@ -166,6 +166,103 @@ static boolean SetHTTPResponseBody(struct HttpResponse *response, char *buffer,
   return TRUE;
 }
 
+static int GetHttpResponse(TCPsocket socket, char *buffer, int max_buffer_size)
+{
+  char *buffer_ptr = buffer;
+  int buffer_left = max_buffer_size;
+  int buffer_size = 0;
+  int response_size = 0;
+
+  while (1)
+  {
+    // read as many bytes to the buffer as possible
+    int bytes = SDLNet_TCP_Recv(socket, buffer_ptr, buffer_left);
+
+    if (bytes <= 0)
+    {
+      SetHttpError("receiving response from server failed");
+
+      return -1;
+    }
+
+    buffer_ptr += bytes;
+    buffer_size += bytes;
+    buffer_left -= bytes;
+
+    // check if response size was already determined
+    if (response_size > 0)
+    {
+      // check if response data was completely received
+      if (buffer_size >= response_size)
+       break;
+
+      // continue reading response body from server
+      continue;
+    }
+
+    char *separator = "\r\n\r\n";
+    char *separator_start = strstr(buffer, separator);
+    int separator_size = strlen(separator);
+
+    // check if response header was completely received
+    if (separator_start == NULL)
+    {
+      // continue reading response header from server
+      continue;
+    }
+
+    char *content_length = "Content-Length: ";
+    char *content_length_start = strstr(buffer, content_length);
+    int head_size = separator_start - buffer;
+
+    // check if response header contains content length header
+    if (content_length_start == NULL ||
+       content_length_start >= buffer + head_size)
+    {
+      SetHttpError("receiving 'Content-Length' header from server failed");
+
+      return -1;
+    }
+
+    char *content_length_value = content_length_start + strlen(content_length);
+    char *content_length_end = strstr(content_length_value, "\r\n");
+
+    // check if content length header has line termination
+    if (content_length_end == NULL)
+    {
+      SetHttpError("receiving 'Content-Length' value from server failed");
+
+      return -1;
+    }
+
+    int value_len = content_length_end - content_length_value;
+    int max_value_len = 10;
+
+    // check if content length header has valid size
+    if (value_len > max_value_len)
+    {
+      SetHttpError("received invalid 'Content-Length' value from server");
+
+      return -1;
+    }
+
+    char value_str[value_len + 1];
+
+    strncpy(value_str, content_length_value, value_len);
+    value_str[value_len] = '\0';
+
+    int body_size = atoi(value_str);
+
+    response_size = head_size + separator_size + body_size;
+
+    // check if response data was completely received
+    if (buffer_size >= response_size)
+      break;
+  }
+
+  return buffer_size;
+}
+
 static boolean DoHttpRequestExt(struct HttpRequest *request,
                                struct HttpResponse *response,
                                char *send_buffer,
@@ -251,11 +348,11 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
     return FALSE;
   }
 
-  int recv_bytes = SDLNet_TCP_Recv(*socket, recv_buffer, max_http_buffer_size);
+  int recv_bytes = GetHttpResponse(*socket, recv_buffer, max_http_buffer_size);
 
   if (recv_bytes <= 0)
   {
-    SetHttpError("receiving response from server failed");
+    // HTTP error already set in GetHttpResponse()
 
     return FALSE;
   }
@@ -296,9 +393,9 @@ static boolean DoHttpRequestExt(struct HttpRequest *request,
 boolean DoHttpRequest(struct HttpRequest *request,
                      struct HttpResponse *response)
 {
-  int max_http_buffer_size = MAX_HTTP_HEAD_SIZE + MAX_HTTP_BODY_SIZE;
-  char *send_buffer = checked_malloc(max_http_buffer_size + 1);
-  char *recv_buffer = checked_malloc(max_http_buffer_size + 1);
+  int max_http_buffer_size = MAX_HTTP_HEAD_SIZE + 2 + MAX_HTTP_BODY_SIZE + 1;
+  char *send_buffer = checked_malloc(max_http_buffer_size);
+  char *recv_buffer = checked_malloc(max_http_buffer_size);
   SDLNet_SocketSet socket_set = NULL;
   TCPsocket socket = NULL;
 
index 1a61ff922ed15ce71d9b734f95e7f7ab80c184ea..4cc613e70062f8031c7703b7fbde5218b664f3dd 100644 (file)
@@ -139,13 +139,6 @@ char *getTokenFromImageID(int graphic)
   return (file_list != NULL ? file_list->token : NULL);
 }
 
-char *getFilenameFromImageID(int graphic)
-{
-  struct FileInfo *file_list = getImageListEntryFromImageID(graphic);
-
-  return (file_list != NULL ? file_list->filename : NULL);
-}
-
 int getImageIDFromToken(char *token)
 {
   struct FileInfo *file_list = image_info->file_list;
@@ -398,9 +391,11 @@ void ScaleImage(int pos, int zoom_factor)
     return;
 
   if (zoom_factor != 1)
+  {
     ScaleBitmap(img_info->bitmaps, zoom_factor);
 
-  img_info->scaled_up = TRUE;
+    img_info->scaled_up = TRUE;
+  }
 }
 
 void FreeAllImages(void)
index cf95a106b44c21f09c7cf263a9d7efb99b6fa184..04952e74882e0535b766c4a6a687dd4311f53379 100644 (file)
@@ -49,6 +49,9 @@
 // this bitmap pointer points to the bitmap with default image size
 #define IMG_BITMAP_STANDARD    IMG_BITMAP_32x32
 
+// maximum number of statically and dynamically defined image files
+#define MAX_IMAGE_FILES                1000000
+
 
 #define GET_BITMAP_ID_FROM_TILESIZE(x) ((x) ==  1 ? IMG_BITMAP_1x1   : \
                                         (x) ==  2 ? IMG_BITMAP_2x2   : \
@@ -73,7 +76,6 @@ Bitmap **getBitmapsFromImageID(int);
 int getOriginalImageWidthFromImageID(int);
 int getOriginalImageHeightFromImageID(int);
 char *getTokenFromImageID(int);
-char *getFilenameFromImageID(int);
 int getImageIDFromToken(char *);
 char *getImageConfigFilename(void);
 int getImageListPropertyMappingSize(void);
index 4a1bc7d5074fcdcbdd0df41599eb72544802cc3e..14ba7d2c61ee9eace068f84767b5176096ea2314 100644 (file)
 // platform independent joystick functions
 // ============================================================================
 
-#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0
-#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1
-
-static void translate_joyname(int *joysymbol, char **name, int mode)
-{
-  static struct
-  {
-    int joysymbol;
-    char *name;
-  } translate_joy[] =
-  {
-    { JOY_LEFT,                "joystick_left" },
-    { JOY_RIGHT,       "joystick_right" },
-    { JOY_UP,          "joystick_up" },
-    { JOY_DOWN,                "joystick_down" },
-    { JOY_BUTTON_1,    "joystick_button_1" },
-    { JOY_BUTTON_2,    "joystick_button_2" },
-  };
-
-  int i;
-
-  if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
-  {
-    *name = "[undefined]";
-
-    for (i = 0; i < 6; i++)
-    {
-      if (*joysymbol == translate_joy[i].joysymbol)
-      {
-       *name = translate_joy[i].name;
-       break;
-      }
-    }
-  }
-  else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
-  {
-    *joysymbol = 0;
-
-    for (i = 0; i < 6; i++)
-    {
-      if (strEqual(*name, translate_joy[i].name))
-      {
-       *joysymbol = translate_joy[i].joysymbol;
-       break;
-      }
-    }
-  }
-}
-
-char *getJoyNameFromJoySymbol(int joysymbol)
-{
-  char *name;
-
-  translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
-  return name;
-}
-
-int getJoySymbolFromJoyName(char *name)
-{
-  int joysymbol;
-
-  translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
-  return joysymbol;
-}
-
 int getJoystickNrFromDeviceName(char *device_name)
 {
   char c;
@@ -173,25 +108,6 @@ static int JoystickPositionPercent(int center, int border, int actual)
   return percent;
 }
 
-void CheckJoystickData(void)
-{
-  int i;
-  int distance = 100;
-
-  for (i = 0; i < MAX_PLAYERS; i++)
-  {
-    if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
-      setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
-    if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
-      setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
-
-    if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
-      setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
-    if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
-      setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
-  }
-}
-
 int JoystickExt(int player_nr, boolean use_as_joystick_nr)
 {
   int joystick_nr = joystick.nr[player_nr];
@@ -305,24 +221,3 @@ int AnyJoystickButton(void)
 
   return result;
 }
-
-void DeactivateJoystick(void)
-{
-  /* Temporarily deactivate joystick. This is needed for calibration
-     screens, where the player has to select a joystick device that
-     should be calibrated. If there is a totally uncalibrated joystick
-     active, it may be impossible (due to messed up input from joystick)
-     to select the joystick device to calibrate even when trying to use
-     the mouse or keyboard to select the device. */
-
-  if (joystick.status & JOYSTICK_AVAILABLE)
-    joystick.status &= ~JOYSTICK_ACTIVE;
-}
-
-void ActivateJoystick(void)
-{
-  // reactivate temporarily deactivated joystick
-
-  if (joystick.status & JOYSTICK_AVAILABLE)
-    joystick.status |= JOYSTICK_ACTIVE;
-}
index e43844edd8b8e63b8d9a10752205162e463b8cd5..6da683f38c9a614c4365e3dcd879ce1fbd3840d2 100644 (file)
 #define JOY_BUTTON_NEW_PRESSED 2
 #define JOY_BUTTON_NEW_RELEASED        3
 
-char *getJoyNameFromJoySymbol(int);
-int getJoySymbolFromJoyName(char *);
 int getJoystickNrFromDeviceName(char *);
 char *getDeviceNameFromJoystickNr(int);
 char *getFormattedJoystickName(const char *);
 
-void CheckJoystickData(void);
 int Joystick(int);
 int JoystickExt(int, boolean);
 int JoystickButton(int);
 int AnyJoystick(void);
 int AnyJoystickButton(void);
 
-void DeactivateJoystick(void);
-void ActivateJoystick(void);
-
 #endif // JOYSTICK_H
index 2573a635b249052532d0101c8414a65378c2d803..390480d4933e6c6a3a36d09900612b30aedd51a1 100644 (file)
@@ -27,6 +27,8 @@
 #include "setup.h"
 #include "misc.h"
 #include "http.h"
+#include "hash.h"
+#include "list.h"
 #include "base64.h"
 #include "zip/miniunz.h"
 
diff --git a/src/libgame/list.c b/src/libgame/list.c
new file mode 100644 (file)
index 0000000..86e7c29
--- /dev/null
@@ -0,0 +1,775 @@
+// ============================================================================
+// list.c
+// ============================================================================
+
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "list.h"
+
+
+/**
+ * List:
+ * @data: holds the element's data, which can be a pointer to any kind
+ *        of data, or any integer value using the
+ *        [Type Conversion Macros][glib-Type-Conversion-Macros]
+ * @next: contains the link to the next element in the list
+ * @prev: contains the link to the previous element in the list
+ *
+ * The #List struct is used for each element in a doubly-linked list.
+ **/
+
+/**
+ * list_previous:
+ * @list: an element in a #List
+ *
+ * A convenience macro to get the previous element in a #List.
+ * Note that it is considered perfectly acceptable to access
+ * @list->prev directly.
+ *
+ * Returns: the previous element, or %NULL if there are no previous
+ *          elements
+ **/
+
+/**
+ * list_next:
+ * @list: an element in a #List
+ *
+ * A convenience macro to get the next element in a #List.
+ * Note that it is considered perfectly acceptable to access
+ * @list->next directly.
+ *
+ * Returns: the next element, or %NULL if there are no more elements
+ **/
+
+/**
+ * list_alloc:
+ *
+ * Allocates space for one #List element. It is called by
+ * list_append(), list_prepend(), list_insert() and
+ * list_insert_sorted() and so is rarely used on its own.
+ *
+ * Returns: a pointer to the newly-allocated #List element
+ **/
+List *
+list_alloc (void)
+{
+  return checked_calloc(sizeof(List));
+}
+
+/**
+ * list_free:
+ * @list: the first link of a #List
+ *
+ * Frees all of the memory used by a #List.
+ * The freed elements are returned to the slice allocator.
+ *
+ * If list elements contain dynamically-allocated memory, you should
+ * either use list_free_full() or free them manually first.
+ *
+ * It can be combined with steal_pointer() to ensure the list head pointer
+ * is not left dangling:
+ * |[<!-- language="C" -->
+ * List *list_of_borrowed_things = â€¦;  /<!-- -->* (transfer container) *<!-- -->/
+ * list_free (steal_pointer (&list_of_borrowed_things));
+ * ]|
+ */
+void
+list_free (List *list)
+{
+  void *slice = list;
+  size_t next_offset = offsetof(List, next);
+
+  while (slice)
+  {
+    void *current = slice;
+    slice = *(void**) (current + next_offset);
+    checked_free(current);
+  }
+}
+
+/**
+ * list_free_1:
+ * @list: a #List element
+ *
+ * Frees one #List element, but does not update links from the next and
+ * previous elements in the list, so you should not call this function on an
+ * element that is currently part of a list.
+ *
+ * It is usually used after list_remove_link().
+ */
+/**
+ * list_free1:
+ *
+ * Another name for list_free_1().
+ **/
+void
+list_free_1 (List *list)
+{
+  checked_free(list);
+}
+
+/**
+ * list_append:
+ * @list: a pointer to a #List
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the end of the list.
+ *
+ * Note that the return value is the new start of the list,
+ * if @list was empty; make sure you store the new value.
+ *
+ * list_append() has to traverse the entire list to find the end,
+ * which is inefficient when adding multiple elements. A common idiom
+ * to avoid the inefficiency is to use list_prepend() and reverse
+ * the list with list_reverse() when all elements have been added.
+ *
+ * |[<!-- language="C" -->
+ * // Notice that these are initialized to the empty list.
+ * List *strinlist = NULL, *number_list = NULL;
+ *
+ * // This is a list of strings.
+ * strinlist = list_append (strinlist, "first");
+ * strinlist = list_append (strinlist, "second");
+ *
+ * // This is a list of integers.
+ * number_list = list_append (number_list, INT_TO_PTR (27));
+ * number_list = list_append (number_list, INT_TO_PTR (14));
+ * ]|
+ *
+ * Returns: either @list or the new start of the #List if @list was %NULL
+ */
+List *
+list_append (List *list, void *data)
+{
+  List *new_list;
+  List *last;
+
+  new_list = checked_malloc(sizeof(List));
+  new_list->data = data;
+  new_list->next = NULL;
+
+  if (list)
+  {
+    last = list_last(list);
+    last->next = new_list;
+    new_list->prev = last;
+
+    return list;
+  }
+  else
+  {
+    new_list->prev = NULL;
+
+    return new_list;
+  }
+}
+
+/**
+ * list_prepend:
+ * @list: a pointer to a #List, this must point to the top of the list
+ * @data: the data for the new element
+ *
+ * Prepends a new element on to the start of the list.
+ *
+ * Note that the return value is the new start of the list,
+ * which will have changed, so make sure you store the new value.
+ *
+ * |[<!-- language="C" -->
+ * // Notice that it is initialized to the empty list.
+ * List *list = NULL;
+ *
+ * list = list_prepend (list, "last");
+ * list = list_prepend (list, "first");
+ * ]|
+ *
+ * Do not use this function to prepend a new element to a different
+ * element than the start of the list. Use list_insert_before() instead.
+ *
+ * Returns: a pointer to the newly prepended element, which is the new
+ *     start of the #List
+ */
+List *
+list_prepend (List *list, void *data)
+{
+  List *new_list;
+
+  new_list = checked_malloc(sizeof(List));
+  new_list->data = data;
+  new_list->next = list;
+
+  if (list)
+  {
+    new_list->prev = list->prev;
+    if (list->prev)
+      list->prev->next = new_list;
+    list->prev = new_list;
+  }
+  else
+  {
+    new_list->prev = NULL;
+  }
+
+  return new_list;
+}
+
+/**
+ * list_insert:
+ * @list: a pointer to a #List, this must point to the top of the list
+ * @data: the data for the new element
+ * @position: the position to insert the element. If this is
+ *     negative, or is larger than the number of elements in the
+ *     list, the new element is added on to the end of the list.
+ *
+ * Inserts a new element into the list at the given position.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_insert (List *list, void *data, int position)
+{
+  List *new_list;
+  List *tmp_list;
+
+  if (position < 0)
+    return list_append(list, data);
+  else if (position == 0)
+    return list_prepend(list, data);
+
+  tmp_list = list_nth(list, position);
+  if (!tmp_list)
+    return list_append(list, data);
+
+  new_list = checked_malloc(sizeof(List));
+  new_list->data = data;
+  new_list->prev = tmp_list->prev;
+  tmp_list->prev->next = new_list;
+  new_list->next = tmp_list;
+  tmp_list->prev = new_list;
+
+  return list;
+}
+
+static inline List *
+_list_remove_link (List *list, List *link)
+{
+  if (link == NULL)
+    return list;
+
+  if (link->prev)
+  {
+    if (link->prev->next == link)
+      link->prev->next = link->next;
+    else
+      Warn("corrupted double-linked list detected");
+  }
+
+  if (link->next)
+  {
+    if (link->next->prev == link)
+      link->next->prev = link->prev;
+    else
+      Warn("corrupted double-linked list detected");
+  }
+
+  if (link == list)
+    list = list->next;
+
+  link->next = NULL;
+  link->prev = NULL;
+
+  return list;
+}
+
+/**
+ * list_remove:
+ * @list: a #List, this must point to the top of the list
+ * @data: the data of the element to remove
+ *
+ * Removes an element from a #List.
+ * If two elements contain the same data, only the first is removed.
+ * If none of the elements contain the data, the #List is unchanged.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove (List *list, const void *data)
+{
+  List *tmp;
+
+  tmp = list;
+  while (tmp)
+  {
+    if (tmp->data != data)
+    {
+      tmp = tmp->next;
+    }
+    else
+    {
+      list = _list_remove_link (list, tmp);
+      free (tmp);
+
+      break;
+    }
+  }
+
+  return list;
+}
+
+/**
+ * list_remove_all:
+ * @list: a #List, this must point to the top of the list
+ * @data: data to remove
+ *
+ * Removes all list nodes with data equal to @data.
+ * Returns the new head of the list. Contrast with
+ * list_remove() which removes only the first node
+ * matching the given data.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove_all (List *list, const void *data)
+{
+  List *tmp = list;
+
+  while (tmp)
+  {
+    if (tmp->data != data)
+    {
+      tmp = tmp->next;
+    }
+    else
+    {
+      List *next = tmp->next;
+
+      if (tmp->prev)
+       tmp->prev->next = next;
+      else
+       list = next;
+
+      if (next)
+       next->prev = tmp->prev;
+
+      free (tmp);
+      tmp = next;
+    }
+  }
+
+  return list;
+}
+
+/**
+ * list_remove_link:
+ * @list: a #List, this must point to the top of the list
+ * @llink: an element in the #List
+ *
+ * Removes an element from a #List, without freeing the element.
+ * The removed element's prev and next links are set to %NULL, so
+ * that it becomes a self-contained list with one element.
+ *
+ * This function is for example used to move an element in the list
+ * (see the example for list_concat()) or to remove an element in
+ * the list before freeing its data:
+ * |[<!-- language="C" -->
+ * list = list_remove_link (list, llink);
+ * free_some_data_that_may_access_the_list_again (llink->data);
+ * list_free (llink);
+ * ]|
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_remove_link (List *list, List *llink)
+{
+  return _list_remove_link(list, llink);
+}
+
+/**
+ * list_delete_link:
+ * @list: a #List, this must point to the top of the list
+ * @link_: node to delete from @list
+ *
+ * Removes the node link_ from the list and frees it.
+ * Compare this to list_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the (possibly changed) start of the #List
+ */
+List *
+list_delete_link (List *list, List *link_)
+{
+  list = _list_remove_link(list, link_);
+  checked_free(link_);
+
+  return list;
+}
+
+/**
+ * list_copy:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Copies a #List.
+ *
+ * Note that this is a "shallow" copy. If the list elements
+ * consist of pointers to data, the pointers are copied but
+ * the actual data is not. See list_copy_deep() if you need
+ * to copy the data as well.
+ *
+ * Returns: the start of the new list that holds the same data as @list
+ */
+List *
+list_copy (List *list)
+{
+  return list_copy_deep(list, NULL, NULL);
+}
+
+/**
+ * g_list_copy_deep:
+ * @list: a #List, this must point to the top of the list
+ * @func: (scope call): a copy function used to copy every element in the list
+ * @user_data: user data passed to the copy function @func, or %NULL
+ *
+ * Makes a full (deep) copy of a #List.
+ *
+ * In contrast with g_list_copy(), this function uses @func to make
+ * a copy of each list element, in addition to copying the list
+ * container itself.
+ *
+ * @func, as a #GCopyFunc, takes two arguments, the data to be copied
+ * and a @user_data pointer. On common processor architectures, it's safe to
+ * pass %NULL as @user_data if the copy function takes only one argument. You
+ * may get compiler warnings from this though if compiling with GCC’s
+ * `-Wcast-function-type` warning.
+ *
+ * For instance, if @list holds a list of GObjects, you can do:
+ * |[<!-- language="C" -->
+ * another_list = g_list_copy_deep (list, (GCopyFunc) g_object_ref, NULL);
+ * ]|
+ *
+ * And, to entirely free the new list, you could do:
+ * |[<!-- language="C" -->
+ * g_list_free_full (another_list, g_object_unref);
+ * ]|
+ *
+ * Returns: the start of the new list that holds a full copy of @list,
+ *     use g_list_free_full() to free it
+ *
+ * Since: 2.34
+ */
+List *
+list_copy_deep (List *list, list_copy_fn func, void *user_data)
+{
+  List *new_list = NULL;
+
+  if (list)
+  {
+    List *last;
+
+    new_list = checked_malloc(sizeof(List));
+
+    if (func)
+      new_list->data = func (list->data, user_data);
+    else
+      new_list->data = list->data;
+
+    new_list->prev = NULL;
+    last = new_list;
+    list = list->next;
+
+    while (list)
+    {
+      last->next = checked_malloc(sizeof(List));
+      last->next->prev = last;
+      last = last->next;
+
+      if (func)
+       last->data = func (list->data, user_data);
+      else
+       last->data = list->data;
+
+      list = list->next;
+    }
+
+    last->next = NULL;
+  }
+
+  return new_list;
+}
+
+/**
+ * list_reverse:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Reverses a #List.
+ * It simply switches the next and prev pointers of each element.
+ *
+ * Returns: the start of the reversed #List
+ */
+List *
+list_reverse (List *list)
+{
+  List *last;
+
+  last = NULL;
+
+  while (list)
+  {
+    last = list;
+    list = last->next;
+    last->next = last->prev;
+    last->prev = list;
+  }
+
+  return last;
+}
+
+/**
+ * list_nth:
+ * @list: a #List, this must point to the top of the list
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element at the given position in a #List.
+ *
+ * This iterates over the list until it reaches the @n-th position. If you
+ * intend to iterate over every element, it is better to use a for-loop as
+ * described in the #List introduction.
+ *
+ * Returns: the element, or %NULL if the position is off
+ *     the end of the #List
+ */
+List *
+list_nth (List *list, unsigned int  n)
+{
+  while ((n-- > 0) && list)
+    list = list->next;
+
+  return list;
+}
+
+/**
+ * list_nth_prev:
+ * @list: a #List
+ * @n: the position of the element, counting from 0
+ *
+ * Gets the element @n places before @list.
+ *
+ * Returns: the element, or %NULL if the position is
+ *     off the end of the #List
+ */
+List *
+list_nth_prev (List *list, unsigned int n)
+{
+  while ((n-- > 0) && list)
+    list = list->prev;
+
+  return list;
+}
+
+/**
+ * list_nth_data:
+ * @list: a #List, this must point to the top of the list
+ * @n: the position of the element
+ *
+ * Gets the data of the element at the given position.
+ *
+ * This iterates over the list until it reaches the @n-th position. If you
+ * intend to iterate over every element, it is better to use a for-loop as
+ * described in the #List introduction.
+ *
+ * Returns: the element's data, or %NULL if the position
+ *     is off the end of the #List
+ */
+void *
+list_nth_data (List *list, unsigned int n)
+{
+  while ((n-- > 0) && list)
+    list = list->next;
+
+  return list ? list->data : NULL;
+}
+
+/**
+ * list_position:
+ * @list: a #List, this must point to the top of the list
+ * @llink: an element in the #List
+ *
+ * Gets the position of the given element
+ * in the #List (starting from 0).
+ *
+ * Returns: the position of the element in the #List,
+ *     or -1 if the element is not found
+ */
+int
+list_position (List *list, List *llink)
+{
+  int i;
+
+  i = 0;
+  while (list)
+  {
+    if (list == llink)
+      return i;
+
+    i++;
+    list = list->next;
+  }
+
+  return -1;
+}
+
+/**
+ * list_index:
+ * @list: a #List, this must point to the top of the list
+ * @data: the data to find
+ *
+ * Gets the position of the element containing
+ * the given data (starting from 0).
+ *
+ * Returns: the index of the element containing the data,
+ *     or -1 if the data is not found
+ */
+int
+list_index (List *list, const void *data)
+{
+  int i;
+
+  i = 0;
+  while (list)
+  {
+    if (list->data == data)
+      return i;
+
+    i++;
+    list = list->next;
+  }
+
+  return -1;
+}
+
+/**
+ * list_last:
+ * @list: any #List element
+ *
+ * Gets the last element in a #List.
+ *
+ * Returns: the last element in the #List,
+ *     or %NULL if the #List has no elements
+ */
+List *
+list_last (List *list)
+{
+  if (list)
+  {
+    while (list->next)
+      list = list->next;
+  }
+
+  return list;
+}
+
+/**
+ * list_first:
+ * @list: any #List element
+ *
+ * Gets the first element in a #List.
+ *
+ * Returns: the first element in the #List,
+ *     or %NULL if the #List has no elements
+ */
+List *
+list_first (List *list)
+{
+  if (list)
+  {
+    while (list->prev)
+      list = list->prev;
+  }
+
+  return list;
+}
+
+/**
+ * list_length:
+ * @list: a #List, this must point to the top of the list
+ *
+ * Gets the number of elements in a #List.
+ *
+ * This function iterates over the whole list to count its elements.
+ * Use a #GQueue instead of a List if you regularly need the number
+ * of items. To check whether the list is non-empty, it is faster to check
+ * @list against %NULL.
+ *
+ * Returns: the number of elements in the #List
+ */
+unsigned int
+list_length (List *list)
+{
+  unsigned int length;
+
+  length = 0;
+  while (list)
+  {
+    length++;
+    list = list->next;
+  }
+
+  return length;
+}
+
+/**
+ * list_foreach:
+ * @list: a #List, this must point to the top of the list
+ * @func: (scope call): the function to call with each element's data
+ * @user_data: user data to pass to the function
+ *
+ * Calls a function for each element of a #List.
+ *
+ * It is safe for @func to remove the element from @list, but it must
+ * not modify any part of the list after that element.
+ */
+/**
+ * list_fn:
+ * @data: the element's data
+ * @user_data: user data passed to list_foreach() or slist_foreach()
+ *
+ * Specifies the type of functions passed to list_foreach() and
+ * slist_foreach().
+ */
+void
+list_foreach (List *list, list_fn func, void *user_data)
+{
+  while (list)
+  {
+    List *next = list->next;
+
+    (*func) (list->data, user_data);
+    list = next;
+  }
+}
diff --git a/src/libgame/list.h b/src/libgame/list.h
new file mode 100644 (file)
index 0000000..2ad694b
--- /dev/null
@@ -0,0 +1,78 @@
+// ============================================================================
+// list.h
+// ============================================================================
+
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+#include "misc.h"
+
+
+typedef struct _List List;
+
+struct _List
+{
+  void *data;
+  List *next;
+  List *prev;
+};
+
+
+typedef void (*list_fn) (void *data, void *userdata);
+typedef void *(*list_copy_fn) (const void *data, void *userdata);
+
+/* Doubly linked lists */
+List *list_alloc(void);
+void  list_free(List *list);
+void  list_free_1(List *list);
+
+List *list_append(List *list, void *data);
+List *list_prepend(List *list, void *data);
+List *list_insert(List *list, void *data, int position);
+List *list_remove(List *list, const void *data);
+List *list_remove_all(List *list, const void *data);
+List *list_remove_link(List *list, List *llink);
+List *list_delete_link(List *list, List *link_);
+List *list_reverse(List *list);
+List *list_copy(List *list);
+List *list_copy_deep(List *list, list_copy_fn func, void *user_data);
+List *list_nth(List *list, unsigned int n);
+List *list_nth_prev(List *list, unsigned int n);
+int   list_position(List *list, List *llink);
+int   list_index(List *list, const void *data);
+List *list_last(List *list);
+List *list_first(List *list);
+unsigned int list_length(List *list);
+void  list_foreach(List *list, list_fn func, void *user_data);
+void *list_nth_data(List *list, unsigned int n);
+
+#define list_previous(list)    ((list) ? (((List *)(list))->prev) : NULL)
+#define list_next(list)                ((list) ? (((List *)(list))->next) : NULL)
+
+#endif
index 8bc457216de7448418ad5cebd885728e562b5b60..5e63c31f93307102d0b9903d12bf8aaebf722d25 100644 (file)
@@ -41,8 +41,7 @@
 // logging functions
 // ----------------------------------------------------------------------------
 
-#define DUPLICATE_LOG_OUT_TO_STDOUT            TRUE
-#define DUPLICATE_LOG_ERR_TO_STDERR            TRUE
+#define DUPLICATE_LOGGING_TO_STDOUT            TRUE
 
 
 #if defined(PLATFORM_ANDROID)
@@ -94,15 +93,15 @@ static void vprintf_log(char *format, va_list ap)
 
 static void vprintf_log_nonewline(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_ERR_ID];
+  FILE *file = program.log_file;
 
-#if DUPLICATE_LOG_ERR_TO_STDERR
-  if (file != program.log_file_default[LOG_ERR_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2);
+    vfprintf(program.log_file_default, format, ap2);
 
     va_end(ap2);
   }
@@ -113,17 +112,17 @@ static void vprintf_log_nonewline(char *format, va_list ap)
 
 static void vprintf_log(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_ERR_ID];
+  FILE *file = program.log_file;
   char *newline = STRING_NEWLINE;
 
-#if DUPLICATE_LOG_ERR_TO_STDERR
-  if (file != program.log_file_default[LOG_ERR_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_ERR_ID], format, ap2);
-    fprintf(program.log_file_default[LOG_ERR_ID], "%s", newline);
+    vfprintf(program.log_file_default, format, ap2);
+    fprintf(program.log_file_default, "%s", newline);
 
     va_end(ap2);
   }
@@ -196,15 +195,15 @@ void printf_line_with_prefix(char *prefix, char *line_chars, int line_length)
 
 static void vPrint(char *format, va_list ap)
 {
-  FILE *file = program.log_file[LOG_OUT_ID];
+  FILE *file = program.log_file;
 
-#if DUPLICATE_LOG_OUT_TO_STDOUT
-  if (file != program.log_file_default[LOG_OUT_ID])
+#if DUPLICATE_LOGGING_TO_STDOUT
+  if (file != program.log_file_default)
   {
     va_list ap2;
     va_copy(ap2, ap);
 
-    vfprintf(program.log_file_default[LOG_OUT_ID], format, ap2);
+    vfprintf(program.log_file_default, format, ap2);
 
     va_end(ap2);
   }
@@ -224,7 +223,7 @@ void Print(char *format, ...)
 
 void PrintNoLog(char *format, ...)
 {
-  FILE *file = program.log_file_default[LOG_OUT_ID];
+  FILE *file = program.log_file_default;
   va_list ap;
 
   va_start(ap, format);
@@ -557,7 +556,12 @@ boolean getTokenValueFromString(char *string, char **token, char **value)
 #define UUID_CHARS             (UUID_BYTES * 2)
 #define UUID_LENGTH            (UUID_CHARS + 4)
 
-char *getUUID(void)
+static unsigned int uuid_random_function(int max)
+{
+  return GetBetterRandom(max);
+}
+
+char *getUUIDExt(unsigned int (*random_function)(int max))
 {
   static char uuid[UUID_LENGTH + 1];
   int data[UUID_BYTES];
@@ -565,7 +569,7 @@ char *getUUID(void)
   int i;
 
   for (i = 0; i < UUID_BYTES; i++)
-    data[i] = GetSimpleRandom(256);
+    data[i] = random_function(256);
 
   data[6] = 0x40 | (data[6] & 0x0f);
   data[8] = 0x80 | (data[8] & 0x3f);
@@ -582,6 +586,11 @@ char *getUUID(void)
   return uuid;
 }
 
+char *getUUID(void)
+{
+  return getUUIDExt(uuid_random_function);
+}
+
 
 // ----------------------------------------------------------------------------
 // counter functions
@@ -611,12 +620,12 @@ static unsigned int mainCounter(int mode)
   return current_ms - base_ms;
 }
 
-void InitCounter()             // set counter back to zero
+void InitCounter(void)         // set counter back to zero
 {
   mainCounter(INIT_COUNTER);
 }
 
-unsigned int Counter() // get milliseconds since last call of InitCounter()
+unsigned int Counter(void)     // get milliseconds since last call of InitCounter()
 {
   return mainCounter(READ_COUNTER);
 }
@@ -631,8 +640,8 @@ void Delay(unsigned int delay)      // Sleep specified number of milliseconds
   sleep_milliseconds(delay);
 }
 
-boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay,
-                       unsigned int actual_counter)
+boolean DelayReachedExt2(unsigned int *counter_var, unsigned int delay,
+                        unsigned int actual_counter)
 {
   if (actual_counter >= *counter_var &&
       actual_counter < *counter_var + delay)
@@ -643,34 +652,40 @@ boolean DelayReachedExt(unsigned int *counter_var, unsigned int delay,
   return TRUE;
 }
 
-boolean FrameReached(unsigned int *frame_counter_var, unsigned int frame_delay)
+boolean DelayReachedExt(DelayCounter *counter, unsigned int actual_counter)
+{
+  return DelayReachedExt2(&counter->count, counter->value, actual_counter);
+}
+
+boolean FrameReached(DelayCounter *counter)
 {
-  return DelayReachedExt(frame_counter_var, frame_delay, FrameCounter);
+  return DelayReachedExt(counter, FrameCounter);
 }
 
-boolean DelayReached(unsigned int *counter_var, unsigned int delay)
+boolean DelayReached(DelayCounter *counter)
 {
-  return DelayReachedExt(counter_var, delay, Counter());
+  return DelayReachedExt(counter, Counter());
 }
 
-void ResetDelayCounterExt(unsigned int *counter_var,
-                         unsigned int actual_counter)
+void ResetDelayCounterExt(DelayCounter *counter, unsigned int actual_counter)
 {
-  DelayReachedExt(counter_var, 0, actual_counter);
+  DelayReachedExt2(&counter->count, 0, actual_counter);
 }
 
-void ResetFrameCounter(unsigned int *frame_counter_var)
+void ResetFrameCounter(DelayCounter *counter)
 {
-  FrameReached(frame_counter_var, 0);
+  ResetDelayCounterExt(counter, FrameCounter);
 }
 
-void ResetDelayCounter(unsigned int *counter_var)
+void ResetDelayCounter(DelayCounter *counter)
 {
-  DelayReached(counter_var, 0);
+  ResetDelayCounterExt(counter, Counter());
 }
 
-int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
+int WaitUntilDelayReached(DelayCounter *counter)
 {
+  unsigned int *counter_var = &counter->count;
+  unsigned int delay = counter->value;
   unsigned int actual_counter;
   int skip_frames = 0;
 
@@ -701,22 +716,22 @@ int WaitUntilDelayReached(unsigned int *counter_var, unsigned int delay)
   return skip_frames;
 }
 
-void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay,
+void SkipUntilDelayReached(DelayCounter *counter,
                           int *loop_var, int last_loop_value)
 {
-  int skip_frames = WaitUntilDelayReached(counter_var, delay);
+  int skip_frames = WaitUntilDelayReached(counter);
 
 #if 0
 #if DEBUG
   if (skip_frames)
     Debug("internal:SkipUntilDelayReached",
          "%d: %d ms -> SKIP %d FRAME(S) [%d ms]",
-         *loop_var, delay,
-         skip_frames, skip_frames * delay);
+         *loop_var, counter->value,
+         skip_frames, skip_frames * counter->value);
   else
     Debug("internal:SkipUntilDelayReached",
          "%d: %d ms",
-         *loop_var, delay);
+         *loop_var, counter->value);
 #endif
 #endif
 
@@ -746,14 +761,14 @@ void SkipUntilDelayReached(unsigned int *counter_var, unsigned int delay,
 // random generator functions
 // ----------------------------------------------------------------------------
 
-unsigned int init_random_number(int nr, int seed)
+static unsigned int init_random_number_ext(int nr, int seed)
 {
   if (seed == NEW_RANDOMIZE)
   {
     // default random seed
     seed = (int)time(NULL);                    // seconds since the epoch
 
-#if !defined(PLATFORM_WIN32)
+#if !defined(PLATFORM_WINDOWS)
     // add some more randomness
     struct timeval current_time;
 
@@ -774,9 +789,32 @@ unsigned int init_random_number(int nr, int seed)
   return (unsigned int) seed;
 }
 
+static unsigned int prng_seed_gettimeofday(void)
+{
+  struct timeval current_time;
+
+  gettimeofday(&current_time, NULL);
+
+  prng_seed_bytes(&current_time, sizeof(current_time));
+
+  return 0;
+}
+
+unsigned int init_random_number(int nr, int seed)
+{
+  return (nr == RANDOM_BETTER ? prng_seed_gettimeofday() :
+         init_random_number_ext(nr, seed));
+}
+
+static unsigned int get_random_number_ext(int nr)
+{
+  return (nr == RANDOM_BETTER ? prng_get_uint() :
+         random_linux_libc(nr));
+}
+
 unsigned int get_random_number(int nr, int max)
 {
-  return (max > 0 ? random_linux_libc(nr) % max : 0);
+  return (max > 0 ? get_random_number_ext(nr) % max : 0);
 }
 
 
@@ -863,7 +901,7 @@ char *getLoginName(void)
 {
   static char *login_name = NULL;
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   if (login_name == NULL)
   {
     unsigned long buffer_size = MAX_USERNAME_LEN + 1;
@@ -894,7 +932,7 @@ char *getRealName(void)
 {
   static char *real_name = NULL;
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   if (real_name == NULL)
   {
     static char buffer[MAX_USERNAME_LEN + 1];
@@ -1050,7 +1088,9 @@ char *getBasePath(char *filename)
 // various string functions
 // ----------------------------------------------------------------------------
 
-char *getStringCat2WithSeparator(char *s1, char *s2, char *sep)
+char *getStringCat2WithSeparator(const char *s1,
+                                const char *s2,
+                                const char *sep)
 {
   if (s1 == NULL || s2 == NULL || sep == NULL)
     return NULL;
@@ -1063,7 +1103,10 @@ char *getStringCat2WithSeparator(char *s1, char *s2, char *sep)
   return complete_string;
 }
 
-char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep)
+char *getStringCat3WithSeparator(const char *s1,
+                                const char *s2,
+                                const char *s3,
+                                const char *sep)
 {
   if (s1 == NULL || s2 == NULL || s3 == NULL || sep == NULL)
     return NULL;
@@ -1077,17 +1120,17 @@ char *getStringCat3WithSeparator(char *s1, char *s2, char *s3, char *sep)
   return complete_string;
 }
 
-char *getStringCat2(char *s1, char *s2)
+char *getStringCat2(const char *s1, const char *s2)
 {
   return getStringCat2WithSeparator(s1, s2, "");
 }
 
-char *getStringCat3(char *s1, char *s2, char *s3)
+char *getStringCat3(const char *s1, const char *s2, const char *s3)
 {
   return getStringCat3WithSeparator(s1, s2, s3, "");
 }
 
-char *getPath2(char *path1, char *path2)
+char *getPath2(const char *path1, const char *path2)
 {
 #if defined(PLATFORM_ANDROID)
   // workaround for reading from assets directory -- skip "." subdirs in path
@@ -1100,7 +1143,7 @@ char *getPath2(char *path1, char *path2)
   return getStringCat2WithSeparator(path1, path2, STRING_PATH_SEPARATOR);
 }
 
-char *getPath3(char *path1, char *path2, char *path3)
+char *getPath3(const char *path1, const char *path2, const char *path3)
 {
 #if defined(PLATFORM_ANDROID)
   // workaround for reading from assets directory -- skip "." subdirs in path
@@ -1128,12 +1171,12 @@ static char *getPngOrPcxIfNotExists(char *filename)
   return filename;
 }
 
-char *getImg2(char *path1, char *path2)
+char *getImg2(const char *path1, const char *path2)
 {
   return getPngOrPcxIfNotExists(getPath2(path1, path2));
 }
 
-char *getImg3(char *path1, char *path2, char *path3)
+char *getImg3(const char *path1, const char *path2, const char *path3)
 {
   return getPngOrPcxIfNotExists(getPath3(path1, path2, path3));
 }
@@ -1177,6 +1220,18 @@ char *getStringCopyNStatic(const char *s, int n)
   return s_copy;
 }
 
+char *getStringToUpper(const char *s)
+{
+  char *s_copy = checked_malloc(strlen(s) + 1);
+  char *s_ptr = s_copy;
+
+  while (*s)
+    *s_ptr++ = toupper(*s++);
+  *s_ptr = '\0';
+
+  return s_copy;
+}
+
 char *getStringToLower(const char *s)
 {
   char *s_copy = checked_malloc(strlen(s) + 1);
@@ -1189,14 +1244,353 @@ char *getStringToLower(const char *s)
   return s_copy;
 }
 
-void setString(char **old_value, char *new_value)
+static char *getStringVPrint(char *format, va_list ap)
+{
+  char s[MAX_LINE_LEN];
+
+  vsnprintf(s, MAX_LINE_LEN, format, ap);      // may truncate output string
+
+  return getStringCopy(s);
+}
+
+char *getStringPrint(char *format, ...)
+{
+  va_list ap;
+  char *s;
+
+  va_start(ap, format);
+  s = getStringVPrint(format, ap);
+  va_end(ap);
+
+  return s;
+}
+
+void setStringPrint(char **s, char *format, ...)
+{
+  va_list ap;
+
+  checked_free(*s);
+
+  va_start(ap, format);
+  *s = getStringVPrint(format, ap);
+  va_end(ap);
+}
+
+void appendStringPrint(char **s_old, char *format, ...)
+{
+  va_list ap;
+  char *s_new;
+
+  va_start(ap, format);
+  s_new = getStringVPrint(format, ap);
+  va_end(ap);
+
+  char *s_combined = getStringCat2(*s_old, s_new);
+
+  checked_free(*s_old);
+  checked_free(s_new);
+
+  *s_old = s_combined;
+}
+
+void setString(char **old_value, const char *new_value)
 {
   checked_free(*old_value);
 
   *old_value = getStringCopy(new_value);
 }
 
-boolean strEqual(char *s1, char *s2)
+char **getSplitStringArray(const char *s, const char *separators, int max_tokens)
+{
+  const char *s_ptr, *s_last = s;
+  byte separator_table[256] = { FALSE };
+  int num_tokens;
+  char **tokens = NULL;
+
+  if (s == NULL)
+    return NULL;
+
+  if (separators == NULL)
+    return NULL;
+
+  if (max_tokens < 1)
+    max_tokens = INT_MAX;
+
+  // if string is empty, return empty array
+  if (*s == '\0')
+  {
+    tokens = checked_malloc(sizeof(char *));
+    tokens[0] = NULL;
+
+    return tokens;
+  }
+
+  // initialize separator table for all characters in separators string
+  for (s_ptr = separators; *s_ptr != '\0'; s_ptr++)
+    separator_table[*(byte *)s_ptr] = TRUE;
+
+  // count number of tokens in string
+  for (num_tokens = 1, s_ptr = s; *s_ptr != '\0'; s_ptr++)
+    if (separator_table[*(byte *)s_ptr] && num_tokens < max_tokens)
+      num_tokens++;
+
+  // allocate array for determined number of tokens
+  tokens = checked_malloc((num_tokens + 1) * sizeof(char *));
+
+  // copy all but last separated sub-strings to array
+  for (num_tokens = 0, s_ptr = s; *s_ptr != '\0'; s_ptr++)
+  {
+    if (separator_table[*(byte *)s_ptr] && num_tokens + 1 < max_tokens)
+    {
+      tokens[num_tokens++] = getStringCopyN(s_last, s_ptr - s_last);
+      s_last = s_ptr + 1;
+    }
+  }
+
+  // copy last separated sub-string to array
+  tokens[num_tokens++] = getStringCopyN(s_last, s_ptr - s_last);
+
+  // terminate array
+  tokens[num_tokens] = NULL;
+
+  return tokens;
+}
+
+int getStringArrayLength(char **s_array)
+{
+  int num_strings = 0;
+
+  if (s_array == NULL)
+    return 0;
+
+  while (s_array[num_strings] != NULL)
+    num_strings++;
+
+  return num_strings;
+}
+
+void freeStringArray(char **s_array)
+{
+  int i;
+
+  if (s_array == NULL)
+    return;
+
+  for (i = 0; s_array[i] != NULL; i++)
+    checked_free(s_array[i]);
+
+  checked_free(s_array);
+}
+
+char *getEscapedString(const char *s)
+{
+  const unsigned char *s_ptr = (unsigned char *)s;
+  char *s_escaped;
+  char *s_escaped_ptr;
+
+  if (s == NULL)
+    return NULL;
+
+  /* Each source byte needs maximally four target chars (\777) */
+  s_escaped = checked_malloc(strlen(s) * 4 + 1);
+  s_escaped_ptr = s_escaped;
+
+  while (*s_ptr != '\0')
+  {
+    switch (*s_ptr)
+    {
+      case '\b':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 'b';
+       break;
+
+      case '\f':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 'f';
+       break;
+
+      case '\n':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 'n';
+       break;
+
+      case '\r':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 'r';
+       break;
+
+      case '\t':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 't';
+       break;
+
+      case '\v':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = 'v';
+       break;
+
+      case '\\':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = '\\';
+       break;
+
+      case '"':
+       *s_escaped_ptr++ = '\\';
+       *s_escaped_ptr++ = '"';
+       break;
+
+      default:
+       if ((*s_ptr < ' ') || (*s_ptr >= 0177))
+       {
+         *s_escaped_ptr++ = '\\';
+         *s_escaped_ptr++ = '0' + (((*s_ptr) >> 6) & 07);
+         *s_escaped_ptr++ = '0' + (((*s_ptr) >> 3) & 07);
+         *s_escaped_ptr++ = '0' + ( (*s_ptr)       & 07);
+       }
+       else
+       {
+         *s_escaped_ptr++ = *s_ptr;
+       }
+       break;
+    }
+
+    s_ptr++;
+  }
+
+  *s_escaped_ptr = '\0';
+
+  return s_escaped;
+}
+
+char *getUnescapedString(const char *s)
+{
+  const char *s_ptr = s;
+  const char *octal_ptr;
+  char *s_unescaped;
+  char *s_unescaped_ptr;
+
+  if (s == NULL)
+    return NULL;
+
+  s_unescaped = checked_malloc(strlen(s) + 1);
+  s_unescaped_ptr = s_unescaped;
+
+  while (*s_ptr != '\0')
+  {
+    if (*s_ptr == '\\')
+    {
+      s_ptr++;
+
+      switch (*s_ptr)
+      {
+       case '\0':
+         Warn("getUnescapedString: trailing \\");
+         goto out;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+         *s_unescaped_ptr = 0;
+         octal_ptr = s_ptr;
+
+         while (s_ptr < octal_ptr + 3 && *s_ptr >= '0' && *s_ptr <= '7')
+         {
+           *s_unescaped_ptr = (*s_unescaped_ptr * 8) + (*s_ptr - '0');
+           s_ptr++;
+         }
+
+         s_unescaped_ptr++;
+         s_ptr--;
+         break;
+
+       case 'b':
+         *s_unescaped_ptr++ = '\b';
+         break;
+
+       case 'f':
+         *s_unescaped_ptr++ = '\f';
+         break;
+
+       case 'n':
+         *s_unescaped_ptr++ = '\n';
+         break;
+
+       case 'r':
+         *s_unescaped_ptr++ = '\r';
+         break;
+
+       case 't':
+         *s_unescaped_ptr++ = '\t';
+         break;
+
+       case 'v':
+         *s_unescaped_ptr++ = '\v';
+         break;
+
+       default:
+         /* also handles \" and \\ */
+         *s_unescaped_ptr++ = *s_ptr;
+         break;
+      }
+    }
+    else
+    {
+      *s_unescaped_ptr++ = *s_ptr;
+    }
+
+    s_ptr++;
+  }
+
+ out:
+  *s_unescaped_ptr = '\0';
+
+  return s_unescaped;
+}
+
+char *chugString(char *s)
+{
+  if (s == NULL)
+    return NULL;
+
+  char *start;
+
+  for (start = (char *)s; *start && isspace(*start); start++)
+    ;
+
+  memmove(s, start, strlen(start) + 1);
+
+  return s;
+}
+
+char *chompString(char *s)
+{
+  if (s == NULL)
+    return NULL;
+
+  int len = strlen(s);
+
+  while (len--)
+  {
+    if (isspace(s[len]))
+      s[len] = '\0';
+    else
+      break;
+  }
+
+  return s;
+}
+
+char *stripString(char *s)
+{
+  return chugString(chompString(s));
+}
+
+boolean strEqual(const char *s1, const char *s2)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1204,7 +1598,7 @@ boolean strEqual(char *s1, char *s2)
          strcmp(s1, s2) == 0);
 }
 
-boolean strEqualN(char *s1, char *s2, int n)
+boolean strEqualN(const char *s1, const char *s2, int n)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1212,7 +1606,7 @@ boolean strEqualN(char *s1, char *s2, int n)
          strncmp(s1, s2, n) == 0);
 }
 
-boolean strEqualCase(char *s1, char *s2)
+boolean strEqualCase(const char *s1, const char *s2)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1220,7 +1614,7 @@ boolean strEqualCase(char *s1, char *s2)
          strcasecmp(s1, s2) == 0);
 }
 
-boolean strEqualCaseN(char *s1, char *s2, int n)
+boolean strEqualCaseN(const char *s1, const char *s2, int n)
 {
   return (s1 == NULL && s2 == NULL ? TRUE  :
          s1 == NULL && s2 != NULL ? FALSE :
@@ -1228,7 +1622,7 @@ boolean strEqualCaseN(char *s1, char *s2, int n)
          strncasecmp(s1, s2, n) == 0);
 }
 
-boolean strPrefix(char *s, char *prefix)
+boolean strPrefix(const char *s, const char *prefix)
 {
   return (s == NULL && prefix == NULL ? TRUE  :
          s == NULL && prefix != NULL ? FALSE :
@@ -1236,7 +1630,7 @@ boolean strPrefix(char *s, char *prefix)
          strncmp(s, prefix, strlen(prefix)) == 0);
 }
 
-boolean strSuffix(char *s, char *suffix)
+boolean strSuffix(const char *s, const char *suffix)
 {
   return (s == NULL && suffix == NULL ? TRUE  :
          s == NULL && suffix != NULL ? FALSE :
@@ -1245,7 +1639,7 @@ boolean strSuffix(char *s, char *suffix)
          strcmp(&s[strlen(s) - strlen(suffix)], suffix) == 0);
 }
 
-boolean strPrefixLower(char *s, char *prefix)
+boolean strPrefixLower(const char *s, const char *prefix)
 {
   char *s_lower = getStringToLower(s);
   boolean match = strPrefix(s_lower, prefix);
@@ -1255,7 +1649,7 @@ boolean strPrefixLower(char *s, char *prefix)
   return match;
 }
 
-boolean strSuffixLower(char *s, char *suffix)
+boolean strSuffixLower(const char *s, const char *suffix)
 {
   char *s_lower = getStringToLower(s);
   boolean match = strSuffix(s_lower, suffix);
@@ -1265,6 +1659,14 @@ boolean strSuffixLower(char *s, char *suffix)
   return match;
 }
 
+boolean isURL(const char *s)
+{
+  while (*s && *s >= 'a' && *s <= 'z')
+    s++;
+
+  return strPrefix(s, "://");
+}
+
 
 // ----------------------------------------------------------------------------
 // command line option handling functions
@@ -1303,6 +1705,8 @@ void GetOptions(int argc, char *argv[],
   options.identifier = NULL;
   options.level_nr = NULL;
 
+  options.display_nr = 0;
+
   options.mytapes = FALSE;
   options.serveronly = FALSE;
   options.network = FALSE;
@@ -1502,7 +1906,29 @@ void GetOptions(int argc, char *argv[],
       if (option_arg == next_option)
        options_left++;
     }
-#if defined(PLATFORM_MACOSX)
+    else if (strncmp(option, "-display", option_len) == 0)
+    {
+      if (option_arg == NULL)
+       FailWithHelp("option '%s' requires an argument", option_str);
+
+      if (option_arg == next_option)
+       options_left++;
+
+      int display_nr = atoi(option_arg);
+
+#if 1
+      // dirty hack: SDL_GetNumVideoDisplays() seems broken on some systems
+      options.display_nr = display_nr;
+#else
+      options.display_nr =
+       MAX(0, MIN(display_nr, SDL_GetNumVideoDisplays() - 1));
+
+      if (display_nr != options.display_nr)
+       Warn("invalid display %d -- using display %d",
+            display_nr, options.display_nr);
+#endif
+    }
+#if defined(PLATFORM_MAC)
     else if (strPrefix(option, "-psn"))
     {
       // ignore process serial number when launched via GUI on Mac OS X
@@ -1576,7 +2002,7 @@ void checked_free(void *ptr)
 
 void clear_mem(void *ptr, unsigned int size)
 {
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   // for unknown reason, memset() sometimes crashes when compiled with MinGW
   char *cptr = (char *)ptr;
 
@@ -1587,6 +2013,19 @@ void clear_mem(void *ptr, unsigned int size)
 #endif
 }
 
+void *get_memcpy(const void *m, size_t size)
+{
+  void *m_copy;
+
+  if (m == NULL)
+    return NULL;
+
+  m_copy = checked_malloc(size);
+  memcpy(m_copy, m, size);
+
+  return m_copy;
+}
+
 
 // ----------------------------------------------------------------------------
 // various helper functions
@@ -1612,6 +2051,31 @@ void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
+int get_number_of_bits(int bits)
+{
+  /*
+    Counting bits set, Brian Kernighan's way
+
+    Brian Kernighan's method goes through as many iterations as there are set
+    bits. So if we have a 32-bit word with only the high bit set, then it will
+    only go once through the loop.
+
+    Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan
+    and Dennis M. Ritchie) mentions this in exercise 2-9.
+    First published by Peter Wegner in CACM 3 (1960), 322.
+  */
+
+  int num_bits = 0;
+
+  while (bits)
+  {
+    bits &= bits - 1;  // clear the least significant bit set
+    num_bits++;
+  }
+
+  return num_bits;
+}
+
 /* the "put" variants of the following file access functions check for the file
    pointer being != NULL and return the number of bytes they have or would have
    written; this allows for chunk writing functions to first determine the size
@@ -1913,6 +2377,64 @@ char *getLatin1FromUTF8(char *utf8)
   return latin1;
 }
 
+int getTextEncoding(char *text)
+{
+  unsigned char *src = (unsigned char *)text;
+  int encoding = TEXT_ENCODING_ASCII;  // default: assume encoding is ASCII
+
+  while (*src)
+  {
+    if (*src >= 128)
+      encoding = TEXT_ENCODING_UTF_8;  // non-ASCII character: assume UTF-8
+
+    if (*src < 128)
+    {
+      src++;
+    }
+    else if (src[0] >= 192 && src[0] < 224 &&
+            src[1] >= 128 && src[1] < 192)
+    {
+      src += 2;
+    }
+    else if (src[0] >= 224 && src[0] < 240 &&
+            src[1] >= 128 && src[1] < 192 &&
+            src[2] >= 128 && src[2] < 192)
+    {
+      src += 3;
+    }
+    else if (src[0] >= 240 && src[0] < 248 &&
+            src[1] >= 128 && src[1] < 192 &&
+            src[2] >= 128 && src[2] < 192 &&
+            src[3] >= 128 && src[3] < 192)
+    {
+      src += 4;
+    }
+    else if (src[0] >= 248 && src[0] < 252 &&
+            src[1] >= 128 && src[1] < 192 &&
+            src[2] >= 128 && src[2] < 192 &&
+            src[3] >= 128 && src[3] < 192 &&
+            src[4] >= 128 && src[4] < 192)
+    {
+      src += 5;
+    }
+    else if (src[0] >= 252 && src[0] < 254 &&
+            src[1] >= 128 && src[1] < 192 &&
+            src[2] >= 128 && src[2] < 192 &&
+            src[3] >= 128 && src[3] < 192 &&
+            src[4] >= 128 && src[4] < 192 &&
+            src[5] >= 128 && src[5] < 192)
+    {
+      src += 6;
+    }
+    else
+    {
+      return TEXT_ENCODING_UNKNOWN;    // non-UTF-8 character: unknown encoding
+    }
+  }
+
+  return encoding;
+}
+
 
 // ----------------------------------------------------------------------------
 // functions for JSON handling
@@ -2394,47 +2916,23 @@ char getValidConfigValueChar(char c)
 
 int get_integer_from_string(char *s)
 {
-  static char *number_text[][3] =
-  {
-    { "0",     "zero",         "null",         },
-    { "1",     "one",          "first"         },
-    { "2",     "two",          "second"        },
-    { "3",     "three",        "third"         },
-    { "4",     "four",         "fourth"        },
-    { "5",     "five",         "fifth"         },
-    { "6",     "six",          "sixth"         },
-    { "7",     "seven",        "seventh"       },
-    { "8",     "eight",        "eighth"        },
-    { "9",     "nine",         "ninth"         },
-    { "10",    "ten",          "tenth"         },
-    { "11",    "eleven",       "eleventh"      },
-    { "12",    "twelve",       "twelfth"       },
-
-    { NULL,    NULL,           NULL            },
-  };
+  // check for the most common case first
+  if (s[0] >= '0' && s[0] <= '9')
+    return atoi(s);
 
-  int i, j;
   char *s_lower = getStringToLower(s);
   int result = -1;
 
-  for (i = 0; number_text[i][0] != NULL; i++)
-    for (j = 0; j < 3; j++)
-      if (strEqual(s_lower, number_text[i][j]))
-       result = i;
-
-  if (result == -1)
-  {
-    if (strEqual(s_lower, "false") ||
-       strEqual(s_lower, "no") ||
-       strEqual(s_lower, "off"))
-      result = 0;
-    else if (strEqual(s_lower, "true") ||
-            strEqual(s_lower, "yes") ||
-            strEqual(s_lower, "on"))
-      result = 1;
-    else
-      result = atoi(s);
-  }
+  if (strEqual(s_lower, "false") ||
+      strEqual(s_lower, "no") ||
+      strEqual(s_lower, "off"))
+    result = 0;
+  else if (strEqual(s_lower, "true") ||
+          strEqual(s_lower, "yes") ||
+          strEqual(s_lower, "on"))
+    result = 1;
+  else
+    result = atoi(s);
 
   free(s_lower);
 
@@ -2457,7 +2955,7 @@ boolean get_boolean_from_string(char *s)
   return result;
 }
 
-int get_switch3_from_string(char *s)
+int get_switch_3_state_from_string(char *s)
 {
   char *s_lower = getStringToLower(s);
   int result = FALSE;
@@ -2468,7 +2966,9 @@ int get_switch3_from_string(char *s)
       get_integer_from_string(s) == 1)
     result = TRUE;
   else if (strEqual(s_lower, "auto"))
-    result = AUTO;
+    result = STATE_AUTO;
+  else if (strEqual(s_lower, "ask"))
+    result = STATE_ASK;
 
   free(s_lower);
 
@@ -2600,7 +3100,7 @@ static void dumpList(ListNode *node_first)
 
 #define MAX_BUFFER_SIZE                        4096
 
-File *openFile(char *filename, char *mode)
+File *openFile(const char *filename, const char *mode)
 {
   File *file = checked_calloc(sizeof(File));
 
@@ -2756,7 +3256,7 @@ char *getStringFromFile(File *file, char *line, int size)
   return fgets(line, size, file->file);
 }
 
-int copyFile(char *filename_from, char *filename_to)
+int copyFile(const char *filename_from, const char *filename_to)
 {
   File *file_from, *file_to;
 
@@ -2786,6 +3286,22 @@ int copyFile(char *filename_from, char *filename_to)
   return 0;
 }
 
+boolean touchFile(const char *filename)
+{
+  FILE *file;
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Warn("cannot touch file '%s'", filename);
+
+    return FALSE;
+  }
+
+  fclose(file);
+
+  return TRUE;
+}
+
 
 // ----------------------------------------------------------------------------
 // functions for directory handling
@@ -2927,7 +3443,7 @@ void freeDirectoryEntry(DirectoryEntry *dir_entry)
 // functions for checking files and filenames
 // ----------------------------------------------------------------------------
 
-boolean directoryExists(char *dir_name)
+boolean directoryExists(const char *dir_name)
 {
   if (dir_name == NULL)
     return FALSE;
@@ -2955,7 +3471,7 @@ boolean directoryExists(char *dir_name)
   return success;
 }
 
-boolean fileExists(char *filename)
+boolean fileExists(const char *filename)
 {
   if (filename == NULL)
     return FALSE;
@@ -2979,7 +3495,7 @@ boolean fileExists(char *filename)
 }
 
 #if 0
-static boolean fileHasPrefix(char *basename, char *prefix)
+static boolean fileHasPrefix(const char *basename, const char *prefix)
 {
   static char *basename_lower = NULL;
   int basename_length, prefix_length;
@@ -3002,7 +3518,7 @@ static boolean fileHasPrefix(char *basename, char *prefix)
 }
 #endif
 
-static boolean fileHasSuffix(char *basename, char *suffix)
+static boolean fileHasSuffix(const char *basename, const char *suffix)
 {
   static char *basename_lower = NULL;
   int basename_length, suffix_length;
@@ -4059,45 +4575,41 @@ void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info)
 // (now also added for Windows, to create files in user data directory)
 // ----------------------------------------------------------------------------
 
+char *getLogBasename(char *basename)
+{
+  return getStringCat2(basename, ".log");
+}
+
 char *getLogFilename(char *basename)
 {
   return getPath2(getMainUserGameDataDir(), basename);
 }
 
-void OpenLogFiles(void)
+void OpenLogFile(void)
 {
-  int i;
-
   InitMainUserDataDirectory();
 
-  for (i = 0; i < NUM_LOGS; i++)
+  if ((program.log_file = fopen(program.log_filename, MODE_WRITE)) == NULL)
   {
-    if ((program.log_file[i] = fopen(program.log_filename[i], MODE_WRITE))
-       == NULL)
-    {
-      program.log_file[i] = program.log_file_default[i];   // reset to default
+    program.log_file = program.log_file_default;   // reset to default
 
-      Warn("cannot open file '%s' for writing: %s",
-          program.log_filename[i], strerror(errno));
-    }
-
-    // output should be unbuffered so it is not truncated in a crash
-    setbuf(program.log_file[i], NULL);
+    Warn("cannot open file '%s' for writing: %s",
+        program.log_filename, strerror(errno));
   }
+
+  // output should be unbuffered so it is not truncated in a crash
+  setbuf(program.log_file, NULL);
 }
 
-void CloseLogFiles(void)
+void CloseLogFile(void)
 {
-  int i;
-
-  for (i = 0; i < NUM_LOGS; i++)
-    if (program.log_file[i] != program.log_file_default[i])
-      fclose(program.log_file[i]);
+  if (program.log_file != program.log_file_default)
+    fclose(program.log_file);
 }
 
-void DumpLogFile(int nr)
+void DumpLogFile(void)
 {
-  FILE *log_file = fopen(program.log_filename[nr], MODE_READ);
+  FILE *log_file = fopen(program.log_filename, MODE_READ);
 
   if (log_file == NULL)
     return;
@@ -4110,12 +4622,12 @@ void DumpLogFile(int nr)
 
 void NotifyUserAboutErrorFile(void)
 {
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   char *title_text = getStringCat2(program.program_title, " Error Message");
   char *error_text = getStringCat2("The program was aborted due to an error; "
                                   "for details, see the following error file:"
                                   STRING_NEWLINE,
-                                  program.log_filename[LOG_ERR_ID]);
+                                  program.log_filename);
 
   MessageBox(NULL, error_text, title_text, MB_OK);
 #endif
index 83b7773018d21f24b374cac499885da11e1a2aac..2b927e57423ed35ac57a8396c2154c854d6e4f91 100644 (file)
 
 #define RANDOM_ENGINE                  0
 #define RANDOM_SIMPLE                  1
+#define RANDOM_BETTER                  2
 
 #define InitEngineRandom(seed)         init_random_number(RANDOM_ENGINE, seed)
 #define InitSimpleRandom(seed)         init_random_number(RANDOM_SIMPLE, seed)
+#define InitBetterRandom(seed)         init_random_number(RANDOM_BETTER, seed)
 #define GetEngineRandom(max)           get_random_number(RANDOM_ENGINE, max)
 #define GetSimpleRandom(max)           get_random_number(RANDOM_SIMPLE, max)
+#define GetBetterRandom(max)           get_random_number(RANDOM_BETTER, max)
 
 // values for getFile...() and putFile...()
 #define BYTE_ORDER_BIG_ENDIAN          0
 #define BIT_ORDER_MSB                  0
 #define BIT_ORDER_LSB                  1
 
+// values for character encoding
+#define TEXT_ENCODING_UNKNOWN          0
+#define TEXT_ENCODING_ASCII            1
+#define TEXT_ENCODING_UTF_8            2
+
 // values for createDirectory()
 #define PERMS_PRIVATE                  0
 #define PERMS_PUBLIC                   1
@@ -120,19 +128,21 @@ int log_2(unsigned int);
 
 boolean getTokenValueFromString(char *, char **, char **);
 
+char *getUUIDExt(unsigned int (*function)(int));
 char *getUUID(void);
 
 void InitCounter(void);
 unsigned int Counter(void);
 void Delay(unsigned int);
-boolean DelayReachedExt(unsigned int *, unsigned int, unsigned int);
-boolean FrameReached(unsigned int *, unsigned int);
-boolean DelayReached(unsigned int *, unsigned int);
-void ResetDelayCounterExt(unsigned int *, unsigned int);
-void ResetFrameCounter(unsigned int *);
-void ResetDelayCounter(unsigned int *);
-int WaitUntilDelayReached(unsigned int *, unsigned int);
-void SkipUntilDelayReached(unsigned int *, unsigned int, int *, int);
+boolean DelayReachedExt2(unsigned int *, unsigned int, unsigned int);
+boolean DelayReachedExt(DelayCounter *, unsigned int);
+boolean FrameReached(DelayCounter *);
+boolean DelayReached(DelayCounter *);
+void ResetDelayCounterExt(DelayCounter *, unsigned int);
+void ResetFrameCounter(DelayCounter *);
+void ResetDelayCounter(DelayCounter *);
+int WaitUntilDelayReached(DelayCounter *);
+void SkipUntilDelayReached(DelayCounter *, int *, int);
 
 unsigned int init_random_number(int, int);
 unsigned int get_random_number(int, int);
@@ -158,27 +168,42 @@ char *getBaseName(char *);
 char *getBaseNamePtr(char *);
 char *getBaseNameNoSuffix(char *);
 
-char *getStringCat2WithSeparator(char *, char *, char *);
-char *getStringCat3WithSeparator(char *, char *, char *, char *);
-char *getStringCat2(char *, char *);
-char *getStringCat3(char *, char *, char *);
-char *getPath2(char *, char *);
-char *getPath3(char *, char *, char*);
-char *getImg2(char *, char *);
-char *getImg3(char *, char *, char*);
+char *getStringCat2WithSeparator(const char *, const char *, const char *);
+char *getStringCat3WithSeparator(const char *, const char *, const char *, const char *);
+char *getStringCat2(const char *, const char *);
+char *getStringCat3(const char *, const char *, const char *);
+char *getPath2(const char *, const char *);
+char *getPath3(const char *, const char *, const char *);
+char *getImg2(const char *, const char *);
+char *getImg3(const char *, const char *, const char *);
 char *getStringCopy(const char *);
 char *getStringCopyN(const char *, int);
 char *getStringCopyNStatic(const char *, int);
+char *getStringToUpper(const char *);
 char *getStringToLower(const char *);
-void setString(char **, char *);
-boolean strEqual(char *, char *);
-boolean strEqualN(char *, char *, int);
-boolean strEqualCase(char *, char *);
-boolean strEqualCaseN(char *, char *, int);
-boolean strPrefix(char *, char *);
-boolean strSuffix(char *, char *);
-boolean strPrefixLower(char *, char *);
-boolean strSuffixLower(char *, char *);
+char *getStringPrint(char *, ...);
+void setStringPrint(char **, char *, ...);
+void appendStringPrint(char **, char *, ...);
+void setString(char **, const char *);
+char **getSplitStringArray(const char *s, const char *, int);
+int getStringArrayLength(char **);
+void freeStringArray(char **);
+char *getEscapedString(const char *);
+char *getUnescapedString(const char *);
+
+char *chugString(char *);
+char *chompString(char *);
+char *stripString(char *);
+
+boolean strEqual(const char *, const char *);
+boolean strEqualN(const char *, const char *, int);
+boolean strEqualCase(const char *, const char *);
+boolean strEqualCaseN(const char *, const char *, int);
+boolean strPrefix(const char *, const char *);
+boolean strSuffix(const char *, const char *);
+boolean strPrefixLower(const char *, const char *);
+boolean strSuffixLower(const char *, const char *);
+boolean isURL(const char *);
 
 void GetOptions(int, char **,
                void (*print_usage_function)(void),
@@ -189,9 +214,11 @@ void *checked_calloc(unsigned int);
 void *checked_realloc(void *, unsigned int);
 void checked_free(void *);
 void clear_mem(void *, unsigned int);
+void *get_memcpy(const void *, size_t);
 
 void swap_numbers(int *, int *);
 void swap_number_pairs(int *, int *, int *, int *);
+int get_number_of_bits(int);
 
 int getFile8BitInteger(File *);
 int putFile8BitInteger(FILE *, int);
@@ -229,6 +256,8 @@ void WriteUnusedBytesToFile(FILE *, unsigned int);
 
 char *getUTF8FromLatin1(char *);
 char *getLatin1FromUTF8(char *);
+int getTextEncoding(char *);
+
 char *getEscapedJSON(char *);
 
 char *getKeyNameFromKey(Key);
@@ -240,7 +269,7 @@ char getValidConfigValueChar(char);
 
 int get_integer_from_string(char *);
 boolean get_boolean_from_string(char *);
-int get_switch3_from_string(char *);
+int get_switch_3_state_from_string(char *);
 int get_player_nr_from_string(char *);
 
 ListNode *newListNode(void);
@@ -249,7 +278,7 @@ void deleteNodeFromList(ListNode **, char *, void (*function)(void *));
 ListNode *getNodeFromKey(ListNode *, char *);
 int getNumNodes(ListNode *);
 
-File *openFile(char *, char *);
+File *openFile(const char *, const char *);
 int closeFile(File *);
 int checkEndOfFile(File *);
 size_t readFile(File *, void *, size_t, size_t);
@@ -257,15 +286,17 @@ size_t writeFile(File *, void *, size_t, size_t);
 int seekFile(File *, long, int);
 int getByteFromFile(File *);
 char *getStringFromFile(File *, char *, int);
-int copyFile(char *, char *);
+int copyFile(const char *, const char *);
+boolean touchFile(const char *);
 
 Directory *openDirectory(char *);
 int closeDirectory(Directory *);
 DirectoryEntry *readDirectory(Directory *);
 void freeDirectoryEntry(DirectoryEntry *);
 
-boolean directoryExists(char *);
-boolean fileExists(char *);
+boolean directoryExists(const char *);
+boolean fileExists(const char *);
+
 boolean FileIsGraphic(char *);
 boolean FileIsSound(char *);
 boolean FileIsMusic(char *);
@@ -280,10 +311,11 @@ void LoadArtworkConfig(struct ArtworkListInfo *);
 void ReloadCustomArtworkList(struct ArtworkListInfo *);
 void FreeCustomArtworkLists(struct ArtworkListInfo *);
 
+char *getLogBasename(char *);
 char *getLogFilename(char *);
-void OpenLogFiles(void);
-void CloseLogFiles(void);
-void DumpLogFile(int);
+void OpenLogFile(void);
+void CloseLogFile(void);
+void DumpLogFile(void);
 
 void NotifyUserAboutErrorFile(void);
 
index ee7bff30dcc1933d361f14d05fc2d40269ca1e96..b9c8a411090f80b5a91a3776d3732d9f2dfe8082 100644 (file)
@@ -16,8 +16,8 @@
 // define main platform keywords
 // ============================================================================
 
-#if defined(WIN32) || defined(_WIN32)
-#define PLATFORM_WIN32
+#if defined(WIN32) || defined(_WIN32) || defined(_WIN64)
+#define PLATFORM_WINDOWS
 #define PLATFORM_STRING "Windows"
 #else
 #define PLATFORM_UNIX
@@ -86,7 +86,7 @@
 #endif
 
 #if defined(__APPLE__) && defined(__MACH__)
-#define PLATFORM_MACOSX
+#define PLATFORM_MAC
 #undef  PLATFORM_STRING
 #define PLATFORM_STRING "Mac"
 #endif
index 7877d82d526218f1f4d8092e2f91fe8eea746470..fd409d06d8a7b3f808f162cd42f30cbee8a017d8 100644 (file)
@@ -9,6 +9,9 @@
 // random.c
 // ============================================================================
 
+#include "random.h"
+
+
 /*
  * Copyright (c) 1983 Regents of the University of California.
  * All rights reserved.
@@ -36,8 +39,6 @@
 #include <limits.h>
 #include <stdlib.h>
 
-#include "random.h"
-
 
 /* An improved random number generation package.  In addition to the standard
    rand()/srand() like interface, this package also has a special state info
@@ -257,3 +258,274 @@ int random_linux_libc(int nr)
     return i;
   }
 }
+
+
+// ============================================================================
+
+/*
+ * prng.c - Portable, ISO C90 and C99 compliant high-quality
+ * pseudo-random number generator based on the alleged RC4
+ * cipher.  This PRNG should be suitable for most general-purpose
+ * uses.  Not recommended for cryptographic or financial
+ * purposes.  Not thread-safe.
+ */
+
+/*
+ * Copyright (c) 2004 Ben Pfaff <blp@cs.stanford.edu>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT
+ * SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <time.h>
+
+/* RC4-based pseudo-random state. */
+static unsigned char s[256];
+static int s_i, s_j;
+
+/* Nonzero if PRNG has been seeded. */
+static int seeded;
+
+/* Swap bytes that A and B point to. */
+#define SWAP_BYTE(A, B)                         \
+        do {                                    \
+                unsigned char swap_temp = *(A); \
+                *(A) = *(B);                    \
+                *(B) = swap_temp;               \
+        } while (0)
+
+/* Seeds the pseudo-random number generator based on the current
+   time.
+
+   If the user calls neither this function nor prng_seed_bytes()
+   before any prng_get*() function, this function is called
+   automatically to obtain a time-based seed. */
+void
+prng_seed_time (void)
+{
+  static time_t t;
+  if (t == 0)
+    t = time (NULL);
+  else
+    t++;
+
+  prng_seed_bytes (&t, sizeof t);
+}
+
+/* Retrieves one octet from the array BYTES, which is N_BYTES in
+   size, starting at an offset of OCTET_IDX octets.  BYTES is
+   treated as a circular array, so that accesses past the first
+   N_BYTES bytes wrap around to the beginning. */
+static unsigned char
+get_octet (const void *bytes_, size_t n_bytes, size_t octet_idx)
+{
+  const unsigned char *bytes = bytes_;
+  if (CHAR_BIT == 8)
+    return bytes[octet_idx % n_bytes];
+  else
+    {
+      size_t first_byte = octet_idx * 8 / CHAR_BIT % n_bytes;
+      size_t start_bit = octet_idx * 8 % CHAR_BIT;
+      unsigned char c = (bytes[first_byte] >> start_bit) & 255;
+
+      size_t bits_filled = CHAR_BIT - start_bit;
+      if (CHAR_BIT % 8 != 0 && bits_filled < 8)
+        {
+          size_t bits_left = 8 - bits_filled;
+          unsigned char bits_left_mask = (1u << bits_left) - 1;
+          size_t second_byte = first_byte + 1 < n_bytes ? first_byte + 1 : 0;
+
+          c |= (bytes[second_byte] & bits_left_mask) << bits_filled;
+        }
+
+      return c;
+    }
+}
+
+/* Seeds the pseudo-random number based on the SIZE bytes in
+   KEY.  At most the first 2048 bits in KEY are used. */
+void
+prng_seed_bytes (const void *key, size_t size)
+{
+  int i, j;
+
+  assert (key != NULL && size > 0);
+
+  for (i = 0; i < 256; i++)
+    s[i] = i;
+  for (i = j = 0; i < 256; i++)
+    {
+      j = (j + s[i] + get_octet (key, size, i)) & 255;
+      SWAP_BYTE (s + i, s + j);
+    }
+
+  s_i = s_j = 0;
+  seeded = 1;
+}
+
+/* Returns a pseudo-random integer in the range [0, 255]. */
+unsigned char
+prng_get_octet (void)
+{
+  if (!seeded)
+    prng_seed_time ();
+
+  s_i = (s_i + 1) & 255;
+  s_j = (s_j + s[s_i]) & 255;
+  SWAP_BYTE (s + s_i, s + s_j);
+
+  return s[(s[s_i] + s[s_j]) & 255];
+}
+
+/* Returns a pseudo-random integer in the range [0, UCHAR_MAX]. */
+unsigned char
+prng_get_byte (void)
+{
+  unsigned byte;
+  int bits;
+
+  byte = prng_get_octet ();
+  for (bits = 8; bits < CHAR_BIT; bits += 8)
+    byte = (byte << 8) | prng_get_octet ();
+  return byte;
+}
+
+/* Fills BUF with SIZE pseudo-random bytes. */
+void
+prng_get_bytes (void *buf_, size_t size)
+{
+  unsigned char *buf;
+
+  for (buf = buf_; size-- > 0; buf++)
+    *buf = prng_get_byte ();
+}
+
+/* Returns a pseudo-random unsigned long in the range [0,
+   ULONG_MAX]. */
+unsigned long
+prng_get_ulong (void)
+{
+  unsigned long ulng;
+  size_t bits;
+
+  ulng = prng_get_octet ();
+  for (bits = 8; bits < CHAR_BIT * sizeof ulng; bits += 8)
+    ulng = (ulng << 8) | prng_get_octet ();
+  return ulng;
+}
+
+/* Returns a pseudo-random long in the range [0, LONG_MAX]. */
+long
+prng_get_long (void)
+{
+  return prng_get_ulong () & LONG_MAX;
+}
+
+/* Returns a pseudo-random unsigned int in the range [0,
+   UINT_MAX]. */
+unsigned
+prng_get_uint (void)
+{
+  unsigned uint;
+  size_t bits;
+
+  uint = prng_get_octet ();
+  for (bits = 8; bits < CHAR_BIT * sizeof uint; bits += 8)
+    uint = (uint << 8) | prng_get_octet ();
+  return uint;
+}
+
+/* Returns a pseudo-random int in the range [0, INT_MAX]. */
+int
+prng_get_int (void)
+{
+  return prng_get_uint () & INT_MAX;
+}
+
+/* Returns a pseudo-random floating-point number from the uniform
+   distribution with range [0,1). */
+double
+prng_get_double (void)
+{
+  for (;;)
+    {
+      double dbl = prng_get_ulong () / (ULONG_MAX + 1.0);
+      if (dbl >= 0.0 && dbl < 1.0)
+        return dbl;
+    }
+}
+
+/* Returns a pseudo-random floating-point number from the
+   distribution with mean 0 and standard deviation 1.  (Multiply
+   the result by the desired standard deviation, then add the
+   desired mean.) */
+double
+prng_get_double_normal (void)
+{
+  /* Knuth, _The Art of Computer Programming_, Vol. 2, 3.4.1C,
+     Algorithm P. */
+  static int has_next = 0;
+  static double next_normal;
+  double this_normal;
+
+  if (has_next)
+    {
+      this_normal = next_normal;
+      has_next = 0;
+    }
+  else
+    {
+      static double limit;
+      double v1, v2, s;
+
+      if (limit == 0.0)
+        limit = log (DBL_MAX / 2) / (DBL_MAX / 2);
+
+      for (;;)
+        {
+          double u1 = prng_get_double ();
+          double u2 = prng_get_double ();
+          v1 = 2.0 * u1 - 1.0;
+          v2 = 2.0 * u2 - 1.0;
+          s = v1 * v1 + v2 * v2;
+          if (s > limit && s < 1)
+            break;
+        }
+
+      this_normal = v1 * sqrt (-2. * log (s) / s);
+      next_normal = v2 * sqrt (-2. * log (s) / s);
+      has_next = 1;
+    }
+
+  return this_normal;
+}
index 63a54c375e093bbaf1c1ad42e4129806dd44665e..0da74da4c83575d94dfe2da8c5b610628d327872 100644 (file)
 void srandom_linux_libc(int, unsigned int);
 int random_linux_libc(int);
 
+
+// ============================================================================
+
+#include <stddef.h>
+
+void prng_seed_time (void);
+void prng_seed_bytes (const void *, size_t);
+unsigned char prng_get_octet (void);
+unsigned char prng_get_byte (void);
+void prng_get_bytes (void *, size_t);
+unsigned long prng_get_ulong (void);
+long prng_get_long (void);
+unsigned prng_get_uint (void);
+int prng_get_int (void);
+double prng_get_double (void);
+double prng_get_double_normal (void);
+
 #endif
index 4108b2b531c533825c092df0ceab9fb1fd596d90..a19defa37acc5a7f7cc8cc07eeb958db0eafe973 100644 (file)
@@ -62,19 +62,33 @@ static void FinalizeScreen(int draw_target)
   if (gfx.draw_global_anim_function != NULL)
     gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_2);
 
-  // copy tile selection cursor to render target buffer, if defined (above all)
+  // copy tile selection cursor to render target buffer, if defined (part 1)
   if (gfx.draw_tile_cursor_function != NULL)
-    gfx.draw_tile_cursor_function(draw_target);
+    gfx.draw_tile_cursor_function(draw_target, TRUE);
+
+  // copy envelope request to render target buffer, if needed (above all)
+  if (gfx.draw_envelope_request_function != NULL)
+    gfx.draw_envelope_request_function(draw_target);
+
+  // copy tile selection cursor to render target buffer, if defined (part 2)
+  if (gfx.draw_tile_cursor_function != NULL)
+    gfx.draw_tile_cursor_function(draw_target, FALSE);
+
+  // copy global animations to render target buffer, if defined (mouse pointer)
+  if (gfx.draw_global_anim_function != NULL)
+    gfx.draw_global_anim_function(draw_target, DRAW_GLOBAL_ANIM_STAGE_3);
 }
 
 static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
 {
-  static unsigned int update_screen_delay = 0;
-  unsigned int update_screen_delay_value = 50;         // (milliseconds)
+  if (program.headless)
+    return;
+
+  static DelayCounter update_screen_delay = { 50 };    // (milliseconds)
   SDL_Surface *screen = backbuffer->surface;
 
   if (limit_screen_updates &&
-      !DelayReached(&update_screen_delay, update_screen_delay_value))
+      !DelayReached(&update_screen_delay))
     return;
 
   LimitScreenUpdates(FALSE);
@@ -151,28 +165,31 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
     dst_rect1 = &dst_rect_screen;
 
 #if defined(HAS_SCREEN_KEYBOARD)
-  if (video.shifted_up || video.shifted_up_delay)
+  SDL_Rect src_rect_up = { 0, 0,  video.width, video.height };
+  SDL_Rect dst_rect_up = dst_rect_screen;
+
+  if (video.shifted_up || video.shifted_up_delay.count)
   {
     int time_current = SDL_GetTicks();
     int pos = video.shifted_up_pos;
     int pos_last = video.shifted_up_pos_last;
 
-    if (!DelayReachedExt(&video.shifted_up_delay, video.shifted_up_delay_value,
-                        time_current))
+    if (!DelayReachedExt(&video.shifted_up_delay, time_current))
     {
-      int delay = time_current - video.shifted_up_delay;
-      int delay_value = video.shifted_up_delay_value;
+      int delay_count = time_current - video.shifted_up_delay.count;
+      int delay_value = video.shifted_up_delay.value;
 
-      pos = pos_last + (pos - pos_last) * delay / delay_value;
+      pos = pos_last + (pos - pos_last) * delay_count / delay_value;
     }
     else
     {
       video.shifted_up_pos_last = pos;
-      video.shifted_up_delay = 0;
+      video.shifted_up_delay.count = 0;
     }
 
-    SDL_Rect src_rect_up = { 0,    pos,  video.width, video.height - pos };
-    SDL_Rect dst_rect_up = { xoff, yoff, video.width, video.height - pos };
+    src_rect_up.y = pos;
+    src_rect_up.h = video.height - pos;
+    dst_rect_up.h = video.height - pos;
 
     if (video.screen_rendering_mode == SPECIAL_RENDERING_TARGET ||
        video.screen_rendering_mode == SPECIAL_RENDERING_DOUBLE)
@@ -221,7 +238,7 @@ static void UpdateScreenExt(SDL_Rect *rect, boolean with_frame_delay)
 
   // global synchronization point of the game to align video frame delay
   if (with_frame_delay)
-    WaitUntilDelayReached(&video.frame_delay, video.frame_delay_value);
+    WaitUntilDelayReached(&video.frame_delay);
 
   video.frame_counter++;
 
@@ -260,7 +277,7 @@ static void SDLSetWindowIcon(char *basename)
   // (setting the window icon on Mac OS X would replace the high-quality
   // dock icon with the currently smaller (and uglier) icon from file)
 
-#if !defined(PLATFORM_MACOSX)
+#if !defined(PLATFORM_MAC)
   char *filename = getCustomImageFilename(basename);
   SDL_Surface *surface;
 
@@ -338,7 +355,7 @@ static boolean SDLHasAlpha(SDL_Surface *surface)
   return (blend_mode == SDL_BLENDMODE_BLEND);
 }
 
-void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
+static void SDLSetSurfaceAlpha(SDL_Surface *surface, boolean set, int alpha)
 {
   SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
 
@@ -346,6 +363,49 @@ void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
   SDL_SetSurfaceAlphaMod(surface, alpha);
 }
 
+static void SDLSetTextureAlpha(SDL_Texture *texture, boolean set, int alpha)
+{
+  SDL_BlendMode blend_mode = (set ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
+
+  SDL_SetTextureBlendMode(texture, blend_mode);
+  SDL_SetTextureAlphaMod(texture, alpha);
+}
+
+static void SDLSetBitmapAlpha(Bitmap *bitmap, boolean is_texture,
+                             boolean is_masked)
+{
+  int alpha_next_blit = bitmap->alpha_next_blit;
+
+  // alpha value must be requested every time before blitting, if needed
+  bitmap->alpha_next_blit = -1;
+
+  // nothing to do if requested alpha value is already set
+  if (bitmap->alpha[is_texture][is_masked] == alpha_next_blit)
+    return;
+
+  // store requested alpha value for masked/unmasked surface/texture
+  bitmap->alpha[is_texture][is_masked] = alpha_next_blit;
+
+  // set blend mode if bitmap is masked or if alpha value is defined
+  boolean set_blend_mode = (is_masked || alpha_next_blit != -1);
+
+  // if alpha value is undefined, use default (opaque) alpha value
+  if (alpha_next_blit == -1)
+    alpha_next_blit = SDL_ALPHA_OPAQUE;
+
+  if (is_texture)
+    SDLSetTextureAlpha(is_masked ? bitmap->texture_masked : bitmap->texture,
+                      set_blend_mode, alpha_next_blit);
+  else
+    SDLSetSurfaceAlpha(is_masked ? bitmap->surface_masked : bitmap->surface,
+                      set_blend_mode, alpha_next_blit);
+}
+
+void SDLSetAlpha(SDL_Surface *surface, boolean set, int alpha)
+{
+  SDLSetSurfaceAlpha(surface, set, alpha);
+}
+
 const char *SDLGetRendererName(void)
 {
   static SDL_RendererInfo renderer_info;
@@ -355,6 +415,25 @@ const char *SDLGetRendererName(void)
   return renderer_info.name;
 }
 
+static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
+{
+  SDL_Surface *new_surface;
+
+  if (surface == NULL)
+    return NULL;
+
+  if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
+    Fail("SDLGetNativeSurface() failed");
+
+  // remove alpha channel from native non-transparent surface, if defined
+  SDLSetAlpha(new_surface, FALSE, 0);
+
+  // remove transparent color from native non-transparent surface, if defined
+  SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
+
+  return new_surface;
+}
+
 SDL_Surface *SDLGetNativeSurface(SDL_Surface *surface)
 {
   SDL_PixelFormat format;
@@ -408,6 +487,46 @@ boolean SDLSetNativeSurface(SDL_Surface **surface)
   return TRUE;
 }
 
+SDL_Surface *SDLCreateNativeSurface(int width, int height, int depth)
+{
+  if (program.headless)
+    return NULL;
+
+  SDL_Surface *surface = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
+
+  if (surface == NULL)
+    Fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+  SDLSetNativeSurface(&surface);
+
+  return surface;
+}
+
+Bitmap *SDLGetBitmapFromSurface(SDL_Surface *surface)
+{
+  int width  = surface->w;
+  int height = surface->h;
+  int depth  = video.default_depth;
+  Bitmap *bitmap = CreateBitmap(width, height, depth);
+
+  // free default surface (not needed anymore)
+  SDL_FreeSurface(bitmap->surface);
+
+  // get native, non-transparent surface from original surface
+  bitmap->surface = SDLGetOpaqueSurface(surface);
+
+  // get native, potentially transparent surface from original surface
+  bitmap->surface_masked = SDLGetNativeSurface(surface);
+
+  // set black pixel to transparent if no alpha channel / transparent color
+  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));
+
+  return bitmap;
+}
+
 static SDL_Texture *SDLCreateTextureFromSurface(SDL_Surface *surface)
 {
   if (program.headless)
@@ -551,6 +670,7 @@ static boolean SDLCreateScreen(boolean fullscreen)
   int screen_height = video.screen_height;
   int surface_flags = (fullscreen ? surface_flags_fullscreen :
                       surface_flags_window);
+  int display_nr = options.display_nr;
 
   // default window size is unscaled
   video.window_width  = screen_width;
@@ -586,15 +706,14 @@ static boolean SDLCreateScreen(boolean fullscreen)
 
     if (sdl_window)
     {
-      SDL_DestroyWindow(sdl_window);
-      sdl_window = NULL;
+      SDL_SetWindowSize(sdl_window, video.window_width, video.window_height);
     }
   }
 
   if (sdl_window == NULL)
     sdl_window = SDL_CreateWindow(program.window_title,
-                                 SDL_WINDOWPOS_CENTERED,
-                                 SDL_WINDOWPOS_CENTERED,
+                                 SDL_WINDOWPOS_CENTERED_DISPLAY(display_nr),
+                                 SDL_WINDOWPOS_CENTERED_DISPLAY(display_nr),
                                  video.window_width,
                                  video.window_height,
                                  surface_flags);
@@ -794,7 +913,8 @@ void SDLSetWindowFullscreen(boolean fullscreen)
   {
     SDLSetWindowScaling(setup.window_scaling_percent);
     SDL_SetWindowPosition(sdl_window,
-                         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
+                         SDL_WINDOWPOS_CENTERED_DISPLAY(options.display_nr),
+                         SDL_WINDOWPOS_CENTERED_DISPLAY(options.display_nr));
 
     video.fullscreen_initial = FALSE;
   }
@@ -919,23 +1039,6 @@ void SDLRedrawWindow(void)
   UpdateScreen_WithoutFrameDelay(NULL);
 }
 
-void SDLCreateBitmapContent(Bitmap *bitmap, int width, int height,
-                           int depth)
-{
-  if (program.headless)
-    return;
-
-  SDL_Surface *surface =
-    SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth, 0,0,0, 0);
-
-  if (surface == NULL)
-    Fail("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
-
-  SDLSetNativeSurface(&surface);
-
-  bitmap->surface = surface;
-}
-
 void SDLFreeBitmapPointers(Bitmap *bitmap)
 {
   if (bitmap->surface)
@@ -955,6 +1058,25 @@ void SDLFreeBitmapPointers(Bitmap *bitmap)
   bitmap->texture_masked = NULL;
 }
 
+void SDLBlitSurface(SDL_Surface *src_surface, SDL_Surface *dst_surface,
+                   int src_x, int src_y, int width, int height,
+                   int dst_x, int dst_y)
+{
+  SDL_Rect src_rect, dst_rect;
+
+  src_rect.x = src_x;
+  src_rect.y = src_y;
+  src_rect.w = width;
+  src_rect.h = height;
+
+  dst_rect.x = dst_x;
+  dst_rect.y = dst_y;
+  dst_rect.w = width;
+  dst_rect.h = height;
+
+  SDL_BlitSurface(src_surface, &src_rect, dst_surface, &dst_rect);
+}
+
 void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                 int src_x, int src_y, int width, int height,
                 int dst_x, int dst_y, int mask_mode)
@@ -972,6 +1094,8 @@ void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   dst_rect.w = width;
   dst_rect.h = height;
 
+  SDLSetBitmapAlpha(src_bitmap, FALSE, mask_mode == BLIT_MASKED);
+
   // if (src_bitmap != backbuffer || dst_bitmap != window)
   if (!(src_bitmap == backbuffer && dst_bitmap == window))
     SDL_BlitSurface((mask_mode == BLIT_MASKED ?
@@ -1006,6 +1130,8 @@ void SDLBlitTexture(Bitmap *bitmap,
   dst_rect.w = width;
   dst_rect.h = height;
 
+  SDLSetBitmapAlpha(bitmap, TRUE, mask_mode == BLIT_MASKED);
+
   SDL_RenderCopy(sdl_renderer, texture, &src_rect, &dst_rect);
 }
 
@@ -1225,6 +1351,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
          draw_border_function();
 
        UpdateScreen_WithFrameDelay(&dst_rect2);
+
+       if (PendingEscapeKeyEvent())
+         break;
       }
     }
   }
@@ -1281,6 +1410,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
 
       // only update the region of the screen that is affected from fading
       UpdateScreen_WithFrameDelay(&dst_rect2);
+
+      if (PendingEscapeKeyEvent())
+       break;
     }
   }
   else         // fading in, fading out or cross-fading
@@ -1307,6 +1439,9 @@ void SDLFadeRectangle(int x, int y, int width, int height,
 
       // only update the region of the screen that is affected from fading
       UpdateScreen_WithFrameDelay(&dst_rect);
+
+      if (PendingEscapeKeyEvent())
+       break;
     }
   }
 
@@ -1370,7 +1505,7 @@ void SDLDrawLines(SDL_Surface *surface, struct XY *points,
          continue;
 
        sge_Line(surface, points[i].x + dx, points[i].y + dy,
-                points[i+1].x + dx, points[i+1].y + dy, color);
+                points[i + 1].x + dx, points[i + 1].y + dy, color);
       }
     }
   }
@@ -1439,14 +1574,14 @@ static void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
       case 1:
       {
        // Assuming 8-bpp
-       *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+       *((Uint8 *)surface->pixels + y * surface->pitch + x) = color;
       }
       break;
 
       case 2:
       {
        // Probably 15-bpp or 16-bpp
-       *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+       *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x) = color;
       }
       break;
 
@@ -1457,20 +1592,20 @@ static void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
        int shift;
 
        // Gack - slow, but endian correct
-       pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+       pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
        shift = surface->format->Rshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Gshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Bshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
       }
       break;
 
       case 4:
       {
        // Probably 32-bpp
-       *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+       *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x) = color;
       }
       break;
     }
@@ -1486,12 +1621,12 @@ static void _PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
 
 static void _PutPixel8(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint8 *)surface->pixels + y*surface->pitch + x) = color;
+  *((Uint8 *)surface->pixels + y * surface->pitch + x) = color;
 }
 
 static void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
+  *((Uint16 *)surface->pixels + y * surface->pitch / 2 + x) = color;
 }
 
 static void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
@@ -1500,38 +1635,38 @@ static void _PutPixel24(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
   int shift;
 
   // Gack - slow, but endian correct
-  pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3;
+  pix = (Uint8 *)surface->pixels + y * surface->pitch + x * 3;
   shift = surface->format->Rshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
   shift = surface->format->Gshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
   shift = surface->format->Bshift;
-  *(pix+shift/8) = color>>shift;
+  *(pix + shift / 8) = color>>shift;
 }
 
 static void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 {
-  *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
+  *((Uint32 *)surface->pixels + y * surface->pitch / 4 + x) = color;
 }
 
-static void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
+static void _PutPixelX(SDL_Surface *dest, Sint16 x, Sint16 y, Uint32 color)
 {
   switch (dest->format->BytesPerPixel)
   {
     case 1:
-      *((Uint8 *)dest->pixels + y*dest->pitch + x) = color;
+      *((Uint8 *)dest->pixels + y * dest->pitch + x) = color;
       break;
 
     case 2:
-      *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
+      *((Uint16 *)dest->pixels + y * dest->pitch / 2 + x) = color;
       break;
 
     case 3:
-      _PutPixel24(dest,x,y,color);
+      _PutPixel24(dest, x, y, color);
       break;
 
     case 4:
-      *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
+      *((Uint32 *)dest->pixels + y * dest->pitch / 4 + x) = color;
       break;
   }
 }
@@ -1569,19 +1704,19 @@ static Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
     switch (dest->format->BytesPerPixel)
     {
       case 1:
-       return y*dest->pitch;
+       return y * dest->pitch;
        break;
 
       case 2:
-       return y*dest->pitch/2;
+       return y * dest->pitch / 2;
        break;
 
       case 3:
-       return y*dest->pitch;
+       return y * dest->pitch;
        break;
 
       case 4:
-       return y*dest->pitch/4;
+       return y * dest->pitch / 4;
        break;
     }
   }
@@ -1617,13 +1752,13 @@ static void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch,
        int shift;
 
        // Gack - slow, but endian correct
-       pix = (Uint8 *)surface->pixels + ypitch + x*3;
+       pix = (Uint8 *)surface->pixels + ypitch + x * 3;
        shift = surface->format->Rshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Gshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
        shift = surface->format->Bshift;
-       *(pix+shift/8) = color>>shift;
+       *(pix + shift / 8) = color>>shift;
       }
       break;
 
@@ -1891,22 +2026,6 @@ void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
 // quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
 // ----------------------------------------------------------------------------
 
-void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
-                  int width, int height, Uint32 color)
-{
-  int x, y;
-
-  for (y = src_y; y < src_y + height; y++)
-  {
-    for (x = src_x; x < src_x + width; x++)
-    {
-      Uint32 pixel = SDLGetPixel(bitmap, x, y);
-
-      SDLPutPixel(bitmap, x, y, pixel == BLACK_PIXEL ? color : BLACK_PIXEL);
-    }
-  }
-}
-
 void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                          int src_x, int src_y, int width, int height,
                          int dst_x, int dst_y)
@@ -2158,7 +2277,7 @@ static int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
 }
 
 // ----------------------------------------------------------------------------
-// zoomSurface()
+// SDLZoomSurface()
 //
 // Zooms a 32bit or 8bit 'src' surface to newly created 'dst' surface.
 // 'zoomx' and 'zoomy' are scaling factors for width and height.
@@ -2166,7 +2285,7 @@ static int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
 // into a 32bit RGBA format on the fly.
 // ----------------------------------------------------------------------------
 
-static SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
+SDL_Surface *SDLZoomSurface(SDL_Surface *src, int dst_width, int dst_height)
 {
   SDL_Surface *zoom_src = NULL;
   SDL_Surface *zoom_dst = NULL;
@@ -2245,25 +2364,6 @@ static SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
   return zoom_dst;
 }
 
-static SDL_Surface *SDLGetOpaqueSurface(SDL_Surface *surface)
-{
-  SDL_Surface *new_surface;
-
-  if (surface == NULL)
-    return NULL;
-
-  if ((new_surface = SDLGetNativeSurface(surface)) == NULL)
-    Fail("SDLGetNativeSurface() failed");
-
-  // remove alpha channel from native non-transparent surface, if defined
-  SDLSetAlpha(new_surface, FALSE, 0);
-
-  // remove transparent color from native non-transparent surface, if defined
-  SDL_SetColorKey(new_surface, UNSET_TRANSPARENT_PIXEL, 0);
-
-  return new_surface;
-}
-
 Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
 {
   Bitmap *dst_bitmap = CreateBitmapStruct();
@@ -2277,7 +2377,7 @@ Bitmap *SDLZoomBitmap(Bitmap *src_bitmap, int dst_width, int dst_height)
   dst_bitmap->height = dst_height;
 
   // create zoomed temporary surface from source surface
-  dst_surface = zoomSurface(src_surface, dst_width, dst_height);
+  dst_surface = SDLZoomSurface(src_surface, dst_width, dst_height);
 
   // create native format destination surface from zoomed temporary surface
   SDLSetNativeSurface(&dst_surface);
@@ -2412,8 +2512,10 @@ void SDLOpenAudio(void)
     return;
   }
 
-  if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
-                   AUDIO_NUM_CHANNELS_STEREO,
+  // set audio sample rate for mixer
+  audio.sample_rate = (setup.audio_sample_rate_44100 ? 44100 : 22050);
+
+  if (Mix_OpenAudio(audio.sample_rate, MIX_DEFAULT_FORMAT, AUDIO_NUM_CHANNELS_STEREO,
                    setup.system.audio_fragment_size) < 0)
   {
     Warn("Mix_OpenAudio() failed: %s", SDL_GetError());
@@ -2443,6 +2545,12 @@ void SDLCloseAudio(void)
   SDL_QuitSubSystem(SDL_INIT_AUDIO);
 }
 
+void SDLReopenAudio(void)
+{
+  SDLCloseAudio();
+  SDLOpenAudio();
+}
+
 
 // ============================================================================
 // event functions
index a5271c8152a1597d81fd585d0465c3c51e9739d6..bbbaa7675919640c264161d7f86a9a467b35669c 100644 (file)
@@ -17,7 +17,7 @@
 #include <SDL_mixer.h>
 #include <SDL_net.h>
 #include <SDL_thread.h>
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
 #include <SDL_syswm.h>
 #endif
 
@@ -75,6 +75,10 @@ struct SDLSurfaceInfo
   char *source_filename;
 
   int width, height;
+
+  int alpha[2][2];             // [surface|texture][opaque|masked]
+  int alpha_next_blit;
+
   SDL_Surface *surface;
   SDL_Surface *surface_masked;
   SDL_Texture *texture;
@@ -395,6 +399,8 @@ void SDLSetAlpha(SDL_Surface *, boolean, int);
 const char *SDLGetRendererName(void);
 boolean SDLSetNativeSurface(SDL_Surface **);
 SDL_Surface *SDLGetNativeSurface(SDL_Surface *);
+SDL_Surface *SDLCreateNativeSurface(int, int, int);
+Bitmap *SDLGetBitmapFromSurface(SDL_Surface *);
 void SDLCreateBitmapTextures(Bitmap *);
 void SDLFreeBitmapTextures(Bitmap *);
 
@@ -416,8 +422,8 @@ void SDLLimitScreenUpdates(boolean);
 void SDLInitVideoDisplay(void);
 void SDLInitVideoBuffer(boolean);
 boolean SDLSetVideoMode(boolean);
-void SDLCreateBitmapContent(Bitmap *, int, int, int);
 void SDLFreeBitmapPointers(Bitmap *);
+void SDLBlitSurface(SDL_Surface *, SDL_Surface *, int, int, int, int, int, int);
 void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
 void SDLBlitTexture(Bitmap *, int, int, int, int, int, int, int);
 void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32);
@@ -428,9 +434,9 @@ void SDLDrawLine(Bitmap *, int, int, int, int, Uint32);
 Pixel SDLGetPixel(Bitmap *, int, int);
 void SDLPutPixel(Bitmap *, int, int, Pixel);
 
-void SDLInvertArea(Bitmap *, int, int, int, int, Uint32);
 void SDLCopyInverseMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
 
+SDL_Surface *SDLZoomSurface(SDL_Surface *, int, int);
 Bitmap *SDLZoomBitmap(Bitmap *, int, int);
 
 Bitmap *SDLLoadImage(char *);
@@ -439,6 +445,7 @@ void SDLSetMouseCursor(struct MouseCursorInfo *);
 
 void SDLOpenAudio(void);
 void SDLCloseAudio(void);
+void SDLReopenAudio(void);
 
 void SDLWaitEvent(Event *);
 void SDLCorrectRawMousePosition(int *, int *);
index 129be747af2f74255697c6e5d804fca741543160..4104a042e8d1d901404d03998280d938b26feb7b 100644 (file)
@@ -19,6 +19,7 @@
 #include "platform.h"
 
 #include "setup.h"
+#include "sound.h"
 #include "joystick.h"
 #include "text.h"
 #include "misc.h"
@@ -47,8 +48,6 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
 #define TOKEN_VALUE_POSITION_DEFAULT           40
 #define TOKEN_COMMENT_POSITION_DEFAULT         60
 
-#define MAX_COOKIE_LEN                         256
-
 #define TREE_NODE_TYPE_DEFAULT                 0
 #define TREE_NODE_TYPE_PARENT                  1
 #define TREE_NODE_TYPE_GROUP                   2
@@ -70,6 +69,7 @@ static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT;
 static SetupFileHash *artworkinfo_cache_old = NULL;
 static SetupFileHash *artworkinfo_cache_new = NULL;
 static SetupFileHash *optional_tokens_hash = NULL;
+static SetupFileHash *missing_file_hash = NULL;
 static boolean use_artworkinfo_cache = TRUE;
 static boolean update_artworkinfo_cache = FALSE;
 
@@ -78,6 +78,16 @@ static boolean update_artworkinfo_cache = FALSE;
 // file functions
 // ----------------------------------------------------------------------------
 
+static void WarnUsingFallback(char *filename)
+{
+  if (getHashEntry(missing_file_hash, filename) == NULL)
+  {
+    setHashEntry(missing_file_hash, filename, "");
+
+    Debug("setup", "cannot find artwork file '%s' (using fallback)", filename);
+  }
+}
+
 static char *getLevelClassDescription(TreeInfo *ti)
 {
   int position = ti->sort_priority / 100;
@@ -140,6 +150,32 @@ static char *getScoreCacheDir(char *level_subdir)
   return score_dir;
 }
 
+static char *getScoreTapeDir(char *level_subdir, int nr)
+{
+  static char *score_tape_dir = NULL;
+  char tape_subdir[MAX_FILENAME_LEN];
+
+  checked_free(score_tape_dir);
+
+  sprintf(tape_subdir, "%03d", nr);
+  score_tape_dir = getPath2(getScoreDir(level_subdir), tape_subdir);
+
+  return score_tape_dir;
+}
+
+static char *getScoreCacheTapeDir(char *level_subdir, int nr)
+{
+  static char *score_cache_tape_dir = NULL;
+  char tape_subdir[MAX_FILENAME_LEN];
+
+  checked_free(score_cache_tape_dir);
+
+  sprintf(tape_subdir, "%03d", nr);
+  score_cache_tape_dir = getPath2(getScoreCacheDir(level_subdir), tape_subdir);
+
+  return score_cache_tape_dir;
+}
+
 static char *getUserSubdir(int nr)
 {
   static char user_subdir[16] = { 0 };
@@ -479,7 +515,7 @@ char *getProgramMainDataPath(char *command_filename, char *base_path)
      set the current working directory to the program package directory) */
   char *main_data_path = getBasePath(command_filename);
 
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
   if (strSuffix(main_data_path, MAC_APP_BINARY_SUBDIR))
   {
     char *main_data_path_old = main_data_path;
@@ -556,6 +592,34 @@ char *getProgramConfigFilename(char *command_filename)
   return config_filename_3;
 }
 
+static char *getPlatformConfigFilename(char *config_filename)
+{
+  static char *platform_config_filename = NULL;
+  static boolean initialized = FALSE;
+
+  if (!initialized)
+  {
+    char *config_basepath = getBasePath(config_filename);
+    char *config_basename = getBaseNameNoSuffix(config_filename);
+    char *config_filename_prefix = getPath2(config_basepath, config_basename);
+    char *platform_string_lower = getStringToLower(PLATFORM_STRING);
+    char *platform_suffix = getStringCat2("-", platform_string_lower);
+
+    platform_config_filename = getStringCat3(config_filename_prefix,
+                                            platform_suffix, ".conf");
+
+    checked_free(config_basepath);
+    checked_free(config_basename);
+    checked_free(config_filename_prefix);
+    checked_free(platform_string_lower);
+    checked_free(platform_suffix);
+
+    initialized = TRUE;
+  }
+
+  return platform_config_filename;
+}
+
 char *getTapeFilename(int nr)
 {
   static char *filename = NULL;
@@ -661,7 +725,7 @@ char *getScoreTapeBasename(char *name)
 
   sprintf(timestamp, "%s", getCurrentTimestamp());
   sprintf(basename_raw, "%s-%s", timestamp, name);
-  sprintf(basename, "%s-%08x", timestamp, get_hash_from_key(basename_raw));
+  sprintf(basename, "%s-%08x", timestamp, get_hash_from_string(basename_raw));
 
   return basename;
 }
@@ -673,10 +737,25 @@ char *getScoreTapeFilename(char *basename_no_ext, int nr)
 
   checked_free(filename);
 
-  sprintf(basename, "%03d.%s.%s", nr, basename_no_ext, TAPEFILE_EXTENSION);
+  sprintf(basename, "%s.%s", basename_no_ext, TAPEFILE_EXTENSION);
 
   // used instead of "leveldir_current->subdir" (for network games)
-  filename = getPath2(getScoreDir(levelset.identifier), basename);
+  filename = getPath2(getScoreTapeDir(levelset.identifier, nr), basename);
+
+  return filename;
+}
+
+char *getScoreCacheTapeFilename(char *basename_no_ext, int nr)
+{
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  checked_free(filename);
+
+  sprintf(basename, "%s.%s", basename_no_ext, TAPEFILE_EXTENSION);
+
+  // used instead of "leveldir_current->subdir" (for network games)
+  filename = getPath2(getScoreCacheTapeDir(levelset.identifier, nr), basename);
 
   return filename;
 }
@@ -697,6 +776,11 @@ char *getDefaultSetupFilename(void)
   return program.config_filename;
 }
 
+char *getPlatformSetupFilename(void)
+{
+  return getPlatformConfigFilename(program.config_filename);
+}
+
 char *getEditorSetupFilename(void)
 {
   static char *filename = NULL;
@@ -735,9 +819,34 @@ char *getHelpTextFilename(void)
   return filename;
 }
 
-char *getLevelSetInfoFilename(void)
+static char *getLevelSetInfoBasename(int nr)
 {
+  static char basename[32];
+
+  sprintf(basename, "levelset_%d.txt", nr + 1);
+
+  return basename;
+}
+
+char *getLevelSetInfoFilename(int nr)
+{
+  char *basename = getLevelSetInfoBasename(nr);
+  static char *info_subdir = NULL;
   static char *filename = NULL;
+
+  if (info_subdir == NULL)
+    info_subdir = getPath2(DOCS_DIRECTORY, LEVELSET_INFO_DIRECTORY);
+
+  checked_free(filename);
+
+  // look for level set info file the current level set directory
+  filename = getPath3(getCurrentLevelDir(), info_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  if (nr > 0)
+    return NULL;
+
   char *basenames[] =
   {
     "README",
@@ -840,6 +949,65 @@ char *getLevelSetTitleMessageFilename(int nr, boolean initial)
   return NULL;         // cannot find specified artwork file anywhere
 }
 
+static char *getCreditsBasename(int nr)
+{
+  static char basename[32];
+
+  sprintf(basename, "credits_%d.txt", nr + 1);
+
+  return basename;
+}
+
+char *getCreditsFilename(int nr, boolean global)
+{
+  char *basename = getCreditsBasename(nr);
+  char *basepath = NULL;
+  static char *credits_subdir = NULL;
+  static char *filename = NULL;
+
+  if (credits_subdir == NULL)
+    credits_subdir = getPath2(DOCS_DIRECTORY, CREDITS_DIRECTORY);
+
+  checked_free(filename);
+
+  // look for credits file in the game's base or current level set directory
+  basepath = (global ? options.base_directory : getCurrentLevelDir());
+
+  filename = getPath3(basepath, credits_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  return NULL;         // cannot find credits file
+}
+
+static char *getProgramInfoBasename(int nr)
+{
+  static char basename[32];
+
+  sprintf(basename, "program_%d.txt", nr + 1);
+
+  return basename;
+}
+
+char *getProgramInfoFilename(int nr)
+{
+  char *basename = getProgramInfoBasename(nr);
+  static char *info_subdir = NULL;
+  static char *filename = NULL;
+
+  if (info_subdir == NULL)
+    info_subdir = getPath2(DOCS_DIRECTORY, PROGRAM_INFO_DIRECTORY);
+
+  checked_free(filename);
+
+  // look for program info file in the game's base directory
+  filename = getPath3(options.base_directory, info_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  return NULL;         // cannot find program info file
+}
+
 static char *getCorrectedArtworkBasename(char *basename)
 {
   return basename;
@@ -904,7 +1072,7 @@ char *getCustomImageFilename(char *basename)
   {
     free(filename);
 
-    Warn("cannot find artwork file '%s' (using fallback)", basename);
+    WarnUsingFallback(basename);
 
     // 6th try: look for fallback artwork in old default artwork directory
     // (needed to prevent errors when trying to access unused artwork files)
@@ -975,7 +1143,7 @@ char *getCustomSoundFilename(char *basename)
   {
     free(filename);
 
-    Warn("cannot find artwork file '%s' (using fallback)", basename);
+    WarnUsingFallback(basename);
 
     // 6th try: look for fallback artwork in old default artwork directory
     // (needed to prevent errors when trying to access unused artwork files)
@@ -1046,7 +1214,7 @@ char *getCustomMusicFilename(char *basename)
   {
     free(filename);
 
-    Warn("cannot find artwork file '%s' (using fallback)", basename);
+    WarnUsingFallback(basename);
 
     // 6th try: look for fallback artwork in old default artwork directory
     // (needed to prevent errors when trying to access unused artwork files)
@@ -1086,7 +1254,58 @@ char *getCustomArtworkLevelConfigFilename(int type)
   return filename;
 }
 
-char *getCustomMusicDirectory(void)
+static boolean directoryExists_CheckMusic(char *directory, boolean check_music)
+{
+  if (!directoryExists(directory))
+    return FALSE;
+
+  if (!check_music)
+    return TRUE;
+
+  Directory *dir;
+  DirectoryEntry *dir_entry;
+  int num_music = getMusicListSize();
+  boolean music_found = FALSE;
+
+  if ((dir = openDirectory(directory)) == NULL)
+    return FALSE;
+
+  while ((dir_entry = readDirectory(dir)) != NULL)     // loop all entries
+  {
+    char *basename = dir_entry->basename;
+    boolean music_already_used = FALSE;
+    int i;
+
+    // skip all music files that are configured in music config file
+    for (i = 0; i < num_music; i++)
+    {
+      struct FileInfo *music = getMusicListEntry(i);
+
+      if (strEqual(basename, music->filename))
+      {
+       music_already_used = TRUE;
+
+       break;
+      }
+    }
+
+    if (music_already_used)
+      continue;
+
+    if (FileIsMusic(dir_entry->filename))
+    {
+      music_found = TRUE;
+
+      break;
+    }
+  }
+
+  closeDirectory(dir);
+
+  return music_found;
+}
+
+static char *getCustomMusicDirectoryExt(boolean check_music)
 {
   static char *directory = NULL;
   boolean skip_setup_artwork = FALSE;
@@ -1097,7 +1316,7 @@ char *getCustomMusicDirectory(void)
   {
     // 1st try: look for special artwork in current level series directory
     directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
-    if (directoryExists(directory))
+    if (directoryExists_CheckMusic(directory, check_music))
       return directory;
 
     free(directory);
@@ -1107,7 +1326,9 @@ char *getCustomMusicDirectory(void)
     {
       // 2nd try: look for special artwork configured in level series config
       directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
-      if (directoryExists(directory))
+
+      // directory also valid if no unconfigured music found (no game music)
+      if (directoryExists_CheckMusic(directory, FALSE))
        return directory;
 
       free(directory);
@@ -1121,7 +1342,9 @@ char *getCustomMusicDirectory(void)
   {
     // 3rd try: look for special artwork in configured artwork directory
     directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
-    if (directoryExists(directory))
+
+    // directory also valid if no unconfigured music found (no game music)
+    if (directoryExists_CheckMusic(directory, FALSE))
       return directory;
 
     free(directory);
@@ -1129,39 +1352,104 @@ char *getCustomMusicDirectory(void)
 
   // 4th try: look for default artwork in new default artwork directory
   directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR));
-  if (directoryExists(directory))
+  if (directoryExists_CheckMusic(directory, check_music))
     return directory;
 
   free(directory);
 
   // 5th try: look for default artwork in old default artwork directory
   directory = getStringCopy(options.music_directory);
-  if (directoryExists(directory))
+  if (directoryExists_CheckMusic(directory, check_music))
     return directory;
 
   return NULL;         // cannot find specified artwork file anywhere
 }
 
+char *getCustomMusicDirectory(void)
+{
+  return getCustomMusicDirectoryExt(FALSE);
+}
+
+char *getCustomMusicDirectory_NoConf(void)
+{
+  return getCustomMusicDirectoryExt(TRUE);
+}
+
+void MarkTapeDirectoryUploadsAsComplete(char *level_subdir)
+{
+  char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+
+  touchFile(filename);
+
+  checked_free(filename);
+}
+
+void MarkTapeDirectoryUploadsAsIncomplete(char *level_subdir)
+{
+  char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+
+  unlink(filename);
+
+  checked_free(filename);
+}
+
+boolean CheckTapeDirectoryUploadsComplete(char *level_subdir)
+{
+  char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+  boolean success = fileExists(filename);
+
+  checked_free(filename);
+
+  return success;
+}
+
+void InitMissingFileHash(void)
+{
+  if (missing_file_hash == NULL)
+    freeSetupFileHash(missing_file_hash);
+
+  missing_file_hash = newSetupFileHash();
+}
+
 void InitTapeDirectory(char *level_subdir)
 {
-  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
-  createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE);
-  createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
+  boolean new_tape_dir = !directoryExists(getTapeDir(level_subdir));
+
+  createDirectory(getUserGameDataDir(), "user data");
+  createDirectory(getTapeDir(NULL), "main tape");
+  createDirectory(getTapeDir(level_subdir), "level tape");
+
+  if (new_tape_dir)
+    MarkTapeDirectoryUploadsAsComplete(level_subdir);
 }
 
 void InitScoreDirectory(char *level_subdir)
 {
-  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
-  createDirectory(getScoreDir(NULL), "main score", PERMS_PRIVATE);
-  createDirectory(getScoreDir(level_subdir), "level score", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data");
+  createDirectory(getScoreDir(NULL), "main score");
+  createDirectory(getScoreDir(level_subdir), "level score");
 }
 
 void InitScoreCacheDirectory(char *level_subdir)
 {
-  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
-  createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
-  createDirectory(getScoreCacheDir(NULL), "main score", PERMS_PRIVATE);
-  createDirectory(getScoreCacheDir(level_subdir), "level score", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data");
+  createDirectory(getCacheDir(), "cache data");
+  createDirectory(getScoreCacheDir(NULL), "main score");
+  createDirectory(getScoreCacheDir(level_subdir), "level score");
+}
+
+void InitScoreTapeDirectory(char *level_subdir, int nr)
+{
+  InitScoreDirectory(level_subdir);
+
+  createDirectory(getScoreTapeDir(level_subdir, nr), "score tape");
+}
+
+void InitScoreCacheTapeDirectory(char *level_subdir, int nr)
+{
+  InitScoreCacheDirectory(level_subdir);
+
+  createDirectory(getScoreCacheTapeDir(level_subdir, nr), "score tape");
 }
 
 static void SaveUserLevelInfo(void);
@@ -1170,12 +1458,15 @@ void InitUserLevelDirectory(char *level_subdir)
 {
   if (!directoryExists(getUserLevelDir(level_subdir)))
   {
-    createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
-    createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
-    createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
+    createDirectory(getMainUserGameDataDir(), "main user data");
+    createDirectory(getUserLevelDir(NULL), "main user level");
 
     if (setup.internal.create_user_levelset)
+    {
+      createDirectory(getUserLevelDir(level_subdir), "user level");
+
       SaveUserLevelInfo();
+    }
   }
 }
 
@@ -1183,24 +1474,24 @@ void InitNetworkLevelDirectory(char *level_subdir)
 {
   if (!directoryExists(getNetworkLevelDir(level_subdir)))
   {
-    createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
-    createDirectory(getNetworkDir(), "network data", PERMS_PRIVATE);
-    createDirectory(getNetworkLevelDir(NULL), "main network level", PERMS_PRIVATE);
-    createDirectory(getNetworkLevelDir(level_subdir), "network level", PERMS_PRIVATE);
+    createDirectory(getMainUserGameDataDir(), "main user data");
+    createDirectory(getNetworkDir(), "network data");
+    createDirectory(getNetworkLevelDir(NULL), "main network level");
+    createDirectory(getNetworkLevelDir(level_subdir), "network level");
   }
 }
 
 void InitLevelSetupDirectory(char *level_subdir)
 {
-  createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
-  createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE);
-  createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE);
+  createDirectory(getUserGameDataDir(), "user data");
+  createDirectory(getLevelSetupDir(NULL), "main level setup");
+  createDirectory(getLevelSetupDir(level_subdir), "level setup");
 }
 
 static void InitCacheDirectory(void)
 {
-  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
-  createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data");
+  createDirectory(getCacheDir(), "cache data");
 }
 
 
@@ -1418,30 +1709,56 @@ static void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets)
   *ti_new = ti_cloned;
 }
 
-static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
+static boolean adjustTreeArtworkForEMC(char **artwork_set_1,
+                                      char **artwork_set_2,
+                                      char **artwork_set, boolean prefer_2)
 {
-  boolean settings_changed = FALSE;
+  // do nothing if neither special artwork set 1 nor 2 are defined
+  if (!*artwork_set_1 && !*artwork_set_2)
+    return FALSE;
 
-  while (node)
+  boolean want_1 = (prefer_2 == FALSE);
+  boolean want_2 = (prefer_2 == TRUE);
+  boolean has_only_1 = (!*artwork_set && !*artwork_set_2);
+  boolean has_only_2 = (!*artwork_set && !*artwork_set_1);
+  char *artwork_set_new = NULL;
+
+  // replace missing special artwork 1 or 2 with (optional) standard artwork
+
+  if (!*artwork_set_1)
+    setString(artwork_set_1, *artwork_set);
+
+  if (!*artwork_set_2)
+    setString(artwork_set_2, *artwork_set);
+
+  // set standard artwork to either special artwork 1 or 2, as requested
+
+  if (*artwork_set_1 && (want_1 || has_only_1))
+    artwork_set_new = *artwork_set_1;
+
+  if (*artwork_set_2 && (want_2 || has_only_2))
+    artwork_set_new = *artwork_set_2;
+
+  if (artwork_set_new && !strEqual(*artwork_set, artwork_set_new))
   {
-    boolean want_ecs = (setup.prefer_aga_graphics == FALSE);
-    boolean want_aga = (setup.prefer_aga_graphics == TRUE);
-    boolean has_only_ecs = (!node->graphics_set && !node->graphics_set_aga);
-    boolean has_only_aga = (!node->graphics_set && !node->graphics_set_ecs);
-    char *graphics_set = NULL;
+    setString(artwork_set, artwork_set_new);
 
-    if (node->graphics_set_ecs && (want_ecs || has_only_ecs))
-      graphics_set = node->graphics_set_ecs;
+    return TRUE;
+  }
 
-    if (node->graphics_set_aga && (want_aga || has_only_aga))
-      graphics_set = node->graphics_set_aga;
+  return FALSE;
+}
 
-    if (graphics_set && !strEqual(node->graphics_set, graphics_set))
-    {
-      setString(&node->graphics_set, graphics_set);
-      settings_changed = TRUE;
-    }
+static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
+{
+  boolean settings_changed = FALSE;
 
+  while (node)
+  {
+    settings_changed |= adjustTreeArtworkForEMC(&node->graphics_set_ecs,
+                                               &node->graphics_set_aga,
+                                               &node->graphics_set,
+                                               setup.prefer_aga_graphics);
     if (node->node_group != NULL)
       settings_changed |= adjustTreeGraphicsForEMC(node->node_group);
 
@@ -1457,24 +1774,10 @@ static boolean adjustTreeSoundsForEMC(TreeInfo *node)
 
   while (node)
   {
-    boolean want_default = (setup.prefer_lowpass_sounds == FALSE);
-    boolean want_lowpass = (setup.prefer_lowpass_sounds == TRUE);
-    boolean has_only_default = (!node->sounds_set && !node->sounds_set_lowpass);
-    boolean has_only_lowpass = (!node->sounds_set && !node->sounds_set_default);
-    char *sounds_set = NULL;
-
-    if (node->sounds_set_default && (want_default || has_only_default))
-      sounds_set = node->sounds_set_default;
-
-    if (node->sounds_set_lowpass && (want_lowpass || has_only_lowpass))
-      sounds_set = node->sounds_set_lowpass;
-
-    if (sounds_set && !strEqual(node->sounds_set, sounds_set))
-    {
-      setString(&node->sounds_set, sounds_set);
-      settings_changed = TRUE;
-    }
-
+    settings_changed |= adjustTreeArtworkForEMC(&node->sounds_set_default,
+                                               &node->sounds_set_lowpass,
+                                               &node->sounds_set,
+                                               setup.prefer_lowpass_sounds);
     if (node->node_group != NULL)
       settings_changed |= adjustTreeSoundsForEMC(node->node_group);
 
@@ -1586,7 +1889,7 @@ void sortTreeInfo(TreeInfo **node_first)
 // some stuff from "files.c"
 // ============================================================================
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
 #ifndef S_IRGRP
 #define S_IRGRP S_IRUSR
 #endif
@@ -1611,7 +1914,7 @@ void sortTreeInfo(TreeInfo **node_first)
 #ifndef S_ISGID
 #define S_ISGID 0
 #endif
-#endif // PLATFORM_WIN32
+#endif // PLATFORM_WINDOWS
 
 // file permissions for newly written files
 #define MODE_R_ALL             (S_IRUSR | S_IRGRP | S_IROTH)
@@ -1635,7 +1938,7 @@ char *getHomeDir(void)
 {
   static char *dir = NULL;
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   if (dir == NULL)
   {
     dir = checked_malloc(MAX_PATH + 1);
@@ -1644,7 +1947,7 @@ char *getHomeDir(void)
       strcpy(dir, ".");
   }
 #elif defined(PLATFORM_EMSCRIPTEN)
-  dir = "/persistent";
+  dir = PERSISTENT_DIRECTORY;
 #elif defined(PLATFORM_UNIX)
   if (dir == NULL)
   {
@@ -1669,7 +1972,7 @@ char *getPersonalDataDir(void)
 {
   static char *personal_data_dir = NULL;
 
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
   if (personal_data_dir == NULL)
     personal_data_dir = getPath2(getHomeDir(), "Documents");
 #else
@@ -1723,7 +2026,7 @@ static mode_t posix_umask(mode_t mask)
 
 static int posix_mkdir(const char *pathname, mode_t mode)
 {
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   return mkdir(pathname);
 #else
   return mkdir(pathname, mode);
@@ -1739,13 +2042,14 @@ static boolean posix_process_running_setgid(void)
 #endif
 }
 
-void createDirectory(char *dir, char *text, int permission_class)
+void createDirectory(char *dir, char *text)
 {
   if (directoryExists(dir))
     return;
 
   // leave "other" permissions in umask untouched, but ensure group parts
   // of USERDATA_DIR_MODE are not masked
+  int permission_class = PERMS_PRIVATE;
   mode_t dir_mode = (permission_class == PERMS_PRIVATE ?
                     DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC);
   mode_t last_umask = posix_umask(0);
@@ -1774,17 +2078,17 @@ void createDirectory(char *dir, char *text, int permission_class)
 
 void InitMainUserDataDirectory(void)
 {
-  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data");
 }
 
 void InitUserDataDirectory(void)
 {
-  createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+  createDirectory(getMainUserGameDataDir(), "main user data");
 
   if (user.nr != 0)
   {
-    createDirectory(getUserDir(-1), "users", PERMS_PRIVATE);
-    createDirectory(getUserDir(user.nr), "user data", PERMS_PRIVATE);
+    createDirectory(getUserDir(-1), "users");
+    createDirectory(getUserDir(user.nr), "user data");
   }
 }
 
@@ -1800,21 +2104,6 @@ void SetFilePermissions(char *filename, int permission_class)
   chmod(filename, perms);
 }
 
-char *getCookie(char *file_type)
-{
-  static char cookie[MAX_COOKIE_LEN + 1];
-
-  if (strlen(program.cookie_prefix) + 1 +
-      strlen(file_type) + strlen("_FILE_VERSION_x.x") > MAX_COOKIE_LEN)
-    return "[COOKIE ERROR]";   // should never happen
-
-  sprintf(cookie, "%s_%s_FILE_VERSION_%d.%d",
-         program.cookie_prefix, file_type,
-         program.version_super, program.version_major);
-
-  return cookie;
-}
-
 void fprintFileHeader(FILE *file, char *basename)
 {
   char *prefix = "# ";
@@ -1992,7 +2281,7 @@ DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char);
 #define remove_hash_entry hashtable_remove
 #endif
 
-unsigned int get_hash_from_key(void *key)
+unsigned int get_hash_from_string(void *key)
 {
   /*
     djb2
@@ -2022,15 +2311,27 @@ unsigned int get_hash_from_key(void *key)
   return hash;
 }
 
-static int keys_are_equal(void *key1, void *key2)
+unsigned int get_hash_from_integer(void *key)
+{
+  unsigned int hash = PTR_TO_UINT(key);
+
+  return hash;
+}
+
+int hash_key_strings_are_equal(void *key1, void *key2)
 {
   return (strEqual((char *)key1, (char *)key2));
 }
 
+int hash_key_integers_are_equal(void *key1, void *key2)
+{
+  return (key1 == key2);
+}
+
 SetupFileHash *newSetupFileHash(void)
 {
   SetupFileHash *new_hash =
-    create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
+    create_hashtable(get_hash_from_string, hash_key_strings_are_equal, free, free);
 
   if (new_hash == NULL)
     Fail("create_hashtable() failed -- out of memory");
@@ -2043,7 +2344,7 @@ void freeSetupFileHash(SetupFileHash *hash)
   if (hash == NULL)
     return;
 
-  hashtable_destroy(hash, 1);  // 1 == also free values stored in hash
+  hashtable_destroy(hash);
 }
 
 char *getHashEntry(SetupFileHash *hash, char *token)
@@ -2069,12 +2370,12 @@ void setHashEntry(SetupFileHash *hash, char *token, char *value)
       Fail("cannot insert into hash -- aborting");
 }
 
-char *removeHashEntry(SetupFileHash *hash, char *token)
+void removeHashEntry(SetupFileHash *hash, char *token)
 {
   if (hash == NULL)
-    return NULL;
+    return;
 
-  return remove_hash_entry(hash, token);
+  remove_hash_entry(hash, token);
 }
 
 #if ENABLE_UNUSED_CODE
@@ -2492,6 +2793,7 @@ SetupFileHash *loadSetupFileHash(char *filename)
 // ============================================================================
 
 #define TOKEN_STR_LAST_LEVEL_SERIES            "last_level_series"
+#define TOKEN_STR_LAST_PLAYED_MENU_USED                "last_played_menu_used"
 #define TOKEN_STR_LAST_PLAYED_LEVEL            "last_played_level"
 #define TOKEN_STR_HANDICAP_LEVEL               "handicap_level"
 #define TOKEN_STR_LAST_USER                    "last_user"
@@ -2524,11 +2826,16 @@ SetupFileHash *loadSetupFileHash(char *filename)
 #define LEVELINFO_TOKEN_FILENAME               24
 #define LEVELINFO_TOKEN_FILETYPE               25
 #define LEVELINFO_TOKEN_SPECIAL_FLAGS          26
-#define LEVELINFO_TOKEN_HANDICAP               27
-#define LEVELINFO_TOKEN_SKIP_LEVELS            28
-#define LEVELINFO_TOKEN_USE_EMC_TILES          29
+#define LEVELINFO_TOKEN_EMPTY_LEVEL_NAME       27
+#define LEVELINFO_TOKEN_FORCE_LEVEL_NAME       28
+#define LEVELINFO_TOKEN_HANDICAP               29
+#define LEVELINFO_TOKEN_TIME_LIMIT             30
+#define LEVELINFO_TOKEN_SKIP_LEVELS            31
+#define LEVELINFO_TOKEN_ALLOW_SKIPPING_LEVELS  32
+#define LEVELINFO_TOKEN_USE_EMC_TILES          33
+#define LEVELINFO_TOKEN_INFO_SCREENS_FROM_MAIN 34
 
-#define NUM_LEVELINFO_TOKENS                   30
+#define NUM_LEVELINFO_TOKENS                   35
 
 static LevelDirTree ldi;
 
@@ -2552,6 +2859,8 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_BOOLEAN,      &ldi.latest_engine,     "latest_engine"         },
   { TYPE_BOOLEAN,      &ldi.level_group,       "level_group"           },
   { TYPE_BOOLEAN,      &ldi.readonly,          "readonly"              },
+  { TYPE_STRING,       &ldi.graphics_set_ecs,  "graphics_set.old"      },
+  { TYPE_STRING,       &ldi.graphics_set_aga,  "graphics_set.new"      },
   { TYPE_STRING,       &ldi.graphics_set_ecs,  "graphics_set.ecs"      },
   { TYPE_STRING,       &ldi.graphics_set_aga,  "graphics_set.aga"      },
   { TYPE_STRING,       &ldi.graphics_set,      "graphics_set"          },
@@ -2562,9 +2871,13 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_STRING,       &ldi.level_filename,    "filename"              },
   { TYPE_STRING,       &ldi.level_filetype,    "filetype"              },
   { TYPE_STRING,       &ldi.special_flags,     "special_flags"         },
+  { TYPE_STRING,       &ldi.empty_level_name,  "empty_level_name"      },
+  { TYPE_BOOLEAN,      &ldi.force_level_name,  "force_level_name"      },
   { TYPE_BOOLEAN,      &ldi.handicap,          "handicap"              },
+  { TYPE_BOOLEAN,      &ldi.time_limit,        "time_limit"            },
   { TYPE_BOOLEAN,      &ldi.skip_levels,       "skip_levels"           },
-  { TYPE_BOOLEAN,      &ldi.use_emc_tiles,     "use_emc_tiles"         }
+  { TYPE_BOOLEAN,      &ldi.use_emc_tiles,     "use_emc_tiles"         },
+  { TYPE_BOOLEAN,      &ldi.info_screens_from_main, "info_screens_from_main" }
 };
 
 static struct TokenInfo artworkinfo_tokens[] =
@@ -2659,6 +2972,9 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type)
 
     ti->special_flags = NULL;
 
+    ti->empty_level_name = NULL;
+    ti->force_level_name = FALSE;
+
     ti->levels = 0;
     ti->first_level = 0;
     ti->last_level = 0;
@@ -2666,9 +2982,11 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type)
     ti->handicap_level = 0;
     ti->readonly = TRUE;
     ti->handicap = TRUE;
+    ti->time_limit = TRUE;
     ti->skip_levels = FALSE;
 
     ti->use_emc_tiles = FALSE;
+    ti->info_screens_from_main = FALSE;
   }
 }
 
@@ -2741,6 +3059,9 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent)
 
     ti->special_flags = getStringCopy(parent->special_flags);
 
+    ti->empty_level_name = getStringCopy(parent->empty_level_name);
+    ti->force_level_name = parent->force_level_name;
+
     ti->levels = parent->levels;
     ti->first_level = parent->first_level;
     ti->last_level = parent->last_level;
@@ -2748,9 +3069,11 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent)
     ti->handicap_level = parent->handicap_level;
     ti->readonly = parent->readonly;
     ti->handicap = parent->handicap;
+    ti->time_limit = parent->time_limit;
     ti->skip_levels = parent->skip_levels;
 
     ti->use_emc_tiles = parent->use_emc_tiles;
+    ti->info_screens_from_main = parent->info_screens_from_main;
   }
 }
 
@@ -2803,6 +3126,9 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti)
 
   ti_copy->special_flags       = getStringCopy(ti->special_flags);
 
+  ti_copy->empty_level_name    = getStringCopy(ti->empty_level_name);
+  ti_copy->force_level_name    = ti->force_level_name;
+
   ti_copy->levels              = ti->levels;
   ti_copy->first_level         = ti->first_level;
   ti_copy->last_level          = ti->last_level;
@@ -2817,9 +3143,11 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti)
   ti_copy->user_defined                = ti->user_defined;
   ti_copy->readonly            = ti->readonly;
   ti_copy->handicap            = ti->handicap;
+  ti_copy->time_limit          = ti->time_limit;
   ti_copy->skip_levels         = ti->skip_levels;
 
   ti_copy->use_emc_tiles       = ti->use_emc_tiles;
+  ti_copy->info_screens_from_main = ti->info_screens_from_main;
 
   ti_copy->color               = ti->color;
   ti_copy->class_desc          = getStringCopy(ti->class_desc);
@@ -2905,8 +3233,8 @@ void setSetupInfo(struct TokenInfo *token_info,
       *(boolean *)setup_value = get_boolean_from_string(token_value);
       break;
 
-    case TYPE_SWITCH3:
-      *(int *)setup_value = get_switch3_from_string(token_value);
+    case TYPE_SWITCH_3_STATES:
+      *(int *)setup_value = get_switch_3_state_from_string(token_value);
       break;
 
     case TYPE_KEY:
@@ -3027,6 +3355,17 @@ static void setTreeInfoParentNodes(TreeInfo *node, TreeInfo *node_parent)
   }
 }
 
+TreeInfo *addTopTreeInfoNode(TreeInfo *node_first)
+{
+  // add top tree node with back link node in previous tree
+  node_first = createTopTreeInfoNode(node_first);
+
+  // set all parent links (back links) in complete tree
+  setTreeInfoParentNodes(node_first, NULL);
+
+  return node_first;
+}
+
 
 // ----------------------------------------------------------------------------
 // functions for handling level and custom artwork info cache
@@ -3666,9 +4005,13 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
                                                    level_directory, ".");
   }
 
-  if (!valid_entry_found)
+  boolean valid_entry_expected =
+    (strEqual(level_directory, options.level_directory) ||
+     setup.internal.create_user_levelset);
+
+  if (valid_entry_expected && !valid_entry_found)
     Warn("cannot find any valid level series in directory '%s'",
-         level_directory);
+        level_directory);
 }
 
 boolean AdjustGraphicsForEMC(void)
@@ -4161,11 +4504,8 @@ static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node)
   LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, TRUE);
   LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, FALSE);
 
-  // add top tree node over all three separate sub-trees
-  *artwork_node = createTopTreeInfoNode(*artwork_node);
-
-  // set all parent links (back links) in complete artwork tree
-  setTreeInfoParentNodes(*artwork_node, NULL);
+  // add top tree node over all sub-trees and set parent links
+  *artwork_node = addTopTreeInfoNode(*artwork_node);
 }
 
 void LoadLevelArtworkInfo(void)
@@ -4269,6 +4609,12 @@ static boolean AddTreeSetToTreeInfoExt(TreeInfo *tree_node_old, char *tree_dir,
   TreeInfo *tree_node_new = getTreeInfoFromIdentifier(*tree_node_first,
                                                      tree_subdir_new);
 
+  // if not found, check if added node is level group or artwork group
+  if (tree_node_new == NULL)
+    tree_node_new = getTreeInfoFromIdentifierExt(*tree_node_first,
+                                                tree_subdir_new,
+                                                TREE_NODE_TYPE_GROUP);
+
   if (tree_node_new == NULL)           // should not happen
     return FALSE;
 
@@ -4422,7 +4768,7 @@ boolean CreateUserLevelSet(char *level_subdir, char *level_name,
   int i;
 
   // create user level sub-directory, if needed
-  createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
+  createDirectory(getUserLevelDir(level_subdir), "user level");
 
   filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME);
 
@@ -4516,9 +4862,10 @@ char *getSetupValue(int type, void *value)
       strcpy(value_string, (*(boolean *)value ? "on" : "off"));
       break;
 
-    case TYPE_SWITCH3:
-      strcpy(value_string, (*(int *)value == AUTO  ? "auto" :
-                           *(int *)value == FALSE ? "off" : "on"));
+    case TYPE_SWITCH_3_STATES:
+      strcpy(value_string, (*(int *)value == STATE_AUTO  ? "auto" :
+                           *(int *)value == STATE_ASK   ? "ask" :
+                           *(int *)value == STATE_FALSE ? "off" : "on"));
       break;
 
     case TYPE_YES_NO:
@@ -4526,12 +4873,17 @@ char *getSetupValue(int type, void *value)
       break;
 
     case TYPE_YES_NO_AUTO:
-      strcpy(value_string, (*(int *)value == AUTO  ? "auto" :
-                           *(int *)value == FALSE ? "no" : "yes"));
+      strcpy(value_string, (*(int *)value == STATE_AUTO  ? "auto" :
+                           *(int *)value == STATE_FALSE ? "no" : "yes"));
+      break;
+
+    case TYPE_YES_NO_ASK:
+      strcpy(value_string, (*(int *)value == STATE_ASK   ? "ask" :
+                           *(int *)value == STATE_FALSE ? "no" : "yes"));
       break;
 
     case TYPE_ECS_AGA:
-      strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS"));
+      strcpy(value_string, (*(boolean *)value ? "new" : "old"));
       break;
 
     case TYPE_KEY:
@@ -4698,33 +5050,51 @@ static void UpdateLastPlayedLevels_List(void)
   setString(&last_level_series[0], leveldir_current->identifier);
 }
 
-static TreeInfo *StoreOrRestoreLastPlayedLevels(TreeInfo *node, boolean store)
+#define LAST_PLAYED_MODE_SET                   1
+#define LAST_PLAYED_MODE_SET_FORCED            2
+#define LAST_PLAYED_MODE_GET                   3
+
+static TreeInfo *StoreOrRestoreLastPlayedLevels(TreeInfo *node, int mode)
 {
   static char *identifier = NULL;
 
-  if (store)
+  if (mode == LAST_PLAYED_MODE_SET)
   {
     setString(&identifier, (node && node->is_copy ? node->identifier : NULL));
-
-    return NULL;       // not used
   }
-  else
+  else if (mode == LAST_PLAYED_MODE_SET_FORCED)
+  {
+    setString(&identifier, (node ? node->identifier : NULL));
+  }
+  else if (mode == LAST_PLAYED_MODE_GET)
   {
     TreeInfo *node_new = getTreeInfoFromIdentifierExt(leveldir_first,
                                                      identifier,
                                                      TREE_NODE_TYPE_COPY);
     return (node_new != NULL ? node_new : node);
   }
+
+  return NULL;         // not used
 }
 
 void StoreLastPlayedLevels(TreeInfo *node)
 {
-  StoreOrRestoreLastPlayedLevels(node, TRUE);
+  StoreOrRestoreLastPlayedLevels(node, LAST_PLAYED_MODE_SET);
+}
+
+void ForcedStoreLastPlayedLevels(TreeInfo *node)
+{
+  StoreOrRestoreLastPlayedLevels(node, LAST_PLAYED_MODE_SET_FORCED);
 }
 
 void RestoreLastPlayedLevels(TreeInfo **node)
 {
-  *node = StoreOrRestoreLastPlayedLevels(*node, FALSE);
+  *node = StoreOrRestoreLastPlayedLevels(*node, LAST_PLAYED_MODE_GET);
+}
+
+boolean CheckLastPlayedLevels(void)
+{
+  return (StoreOrRestoreLastPlayedLevels(NULL, LAST_PLAYED_MODE_GET) != NULL);
 }
 
 void LoadLevelSetup_LastSeries(void)
@@ -4762,6 +5132,13 @@ void LoadLevelSetup_LastSeries(void)
     if (leveldir_current == NULL)
       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
+    char *last_played_menu_used =
+      getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_MENU_USED);
+
+    // store if last level set was selected from "last played" menu
+    if (strEqual(last_played_menu_used, "true"))
+      ForcedStoreLastPlayedLevels(leveldir_current);
+
     for (i = 0; i < MAX_LEVELDIR_HISTORY; i++)
     {
       char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10];
@@ -4824,7 +5201,14 @@ static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series)
     fprintf(file, "# %s\n# ", "the following level set may have caused a problem and was deactivated");
 
   fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
-                                              leveldir_current->identifier));
+                                                leveldir_current->identifier));
+
+  // store if last level set was selected from "last played" menu
+  boolean last_played_menu_used = CheckLastPlayedLevels();
+  char *setup_value = getSetupValue(TYPE_BOOLEAN, &last_played_menu_used);
+
+  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_MENU_USED,
+                                                setup_value));
 
   for (i = 0; last_level_series[i] != NULL; i++)
   {
index 194dea7ebeb0c8fa99e55bc2f25b7ad7ec2614af..c7a5330267f819b55ac46af771399ed01885d1d7 100644 (file)
 // values for setup file handling
 #define TYPE_BOOLEAN                   (1 << 0)
 #define TYPE_SWITCH                    (1 << 1)
-#define TYPE_SWITCH3                   (1 << 2)
+#define TYPE_SWITCH_3_STATES           (1 << 2)
 #define TYPE_YES_NO                    (1 << 3)
 #define TYPE_YES_NO_AUTO               (1 << 4)
-#define TYPE_ECS_AGA                   (1 << 5)
-#define TYPE_KEY                       (1 << 6)
-#define TYPE_KEY_X11                   (1 << 7)
-#define TYPE_INTEGER                   (1 << 8)
-#define TYPE_STRING                    (1 << 9)
-#define TYPE_PLAYER                    (1 << 10)
-#define TYPE_ELEMENT                   (1 << 11)
-#define TYPE_GRAPHIC                   (1 << 12)
+#define TYPE_YES_NO_ASK                        (1 << 5)
+#define TYPE_ECS_AGA                   (1 << 6)
+#define TYPE_KEY                       (1 << 7)
+#define TYPE_KEY_X11                   (1 << 8)
+#define TYPE_INTEGER                   (1 << 9)
+#define TYPE_STRING                    (1 << 10)
+#define TYPE_PLAYER                    (1 << 11)
+#define TYPE_ELEMENT                   (1 << 12)
+#define TYPE_GRAPHIC                   (1 << 13)
 
 // additional values for setup screen
-#define TYPE_ENTER_SCREEN              (1 << 13)
-#define TYPE_LEAVE_SCREEN              (1 << 14)
-#define TYPE_ENTER_MENU                        (1 << 15)
-#define TYPE_LEAVE_MENU                        (1 << 16)
-#define TYPE_ENTER_LIST                        (1 << 17)
-#define TYPE_LEAVE_LIST                        (1 << 18)
-#define TYPE_TEXT_INPUT                        (1 << 19)
-#define TYPE_EMPTY                     (1 << 20)
-#define TYPE_SKIPPABLE                 (1 << 21)
-#define TYPE_KEYTEXT                   (1 << 22)
-#define TYPE_HEADLINE                  (1 << 23)
-
-#define TYPE_GHOSTED                   (1 << 24)
-#define TYPE_QUERY                     (1 << 25)
+#define TYPE_ENTER_SCREEN              (1 << 14)
+#define TYPE_LEAVE_SCREEN              (1 << 15)
+#define TYPE_ENTER_MENU                        (1 << 16)
+#define TYPE_LEAVE_MENU                        (1 << 17)
+#define TYPE_ENTER_LIST                        (1 << 18)
+#define TYPE_LEAVE_LIST                        (1 << 19)
+#define TYPE_TEXT_INPUT                        (1 << 20)
+#define TYPE_EMPTY                     (1 << 21)
+#define TYPE_SKIPPABLE                 (1 << 22)
+#define TYPE_KEYTEXT                   (1 << 23)
+#define TYPE_HEADLINE                  (1 << 24)
+
+#define TYPE_GHOSTED                   (1 << 25)
+#define TYPE_QUERY                     (1 << 26)
 
 // additional values for internal purposes
-#define TYPE_BITFIELD                  (1 << 26)
-#define TYPE_CONTENT                   (1 << 27)
-#define TYPE_ELEMENT_LIST              (1 << 28)
-#define TYPE_CONTENT_LIST              (1 << 29)
+#define TYPE_BITFIELD                  (1 << 27)
+#define TYPE_CONTENT                   (1 << 28)
+#define TYPE_ELEMENT_LIST              (1 << 29)
+#define TYPE_CONTENT_LIST              (1 << 30)
 
 // derived values for setup file handling
 #define TYPE_BOOLEAN_STYLE             (TYPE_BOOLEAN | \
@@ -61,8 +62,9 @@
 
 // derived values for setup screen
 #define TYPE_VALUE                     (TYPE_BOOLEAN_STYLE     | \
-                                        TYPE_SWITCH3           | \
+                                        TYPE_SWITCH_3_STATES   | \
                                         TYPE_YES_NO_AUTO       | \
+                                        TYPE_YES_NO_ASK        | \
                                         TYPE_KEY               | \
                                         TYPE_KEY_X11           | \
                                         TYPE_INTEGER           | \
@@ -272,13 +274,17 @@ char *getScoreFilename(int);
 char *getScoreCacheFilename(int);
 char *getScoreTapeBasename(char *);
 char *getScoreTapeFilename(char *, int);
+char *getScoreCacheTapeFilename(char *, int);
 char *getSetupFilename(void);
 char *getDefaultSetupFilename(void);
+char *getPlatformSetupFilename(void);
 char *getEditorSetupFilename(void);
 char *getHelpAnimFilename(void);
 char *getHelpTextFilename(void);
-char *getLevelSetInfoFilename(void);
+char *getLevelSetInfoFilename(int);
 char *getLevelSetTitleMessageFilename(int, boolean);
+char *getCreditsFilename(int, boolean);
+char *getProgramInfoFilename(int);
 char *getImageFilename(char *);
 char *getCustomImageFilename(char *);
 char *getCustomSoundFilename(char *);
@@ -287,10 +293,18 @@ char *getCustomArtworkFilename(char *, int);
 char *getCustomArtworkConfigFilename(int);
 char *getCustomArtworkLevelConfigFilename(int);
 char *getCustomMusicDirectory(void);
+char *getCustomMusicDirectory_NoConf(void);
 
+void MarkTapeDirectoryUploadsAsComplete(char *);
+void MarkTapeDirectoryUploadsAsIncomplete(char *);
+boolean CheckTapeDirectoryUploadsComplete(char *);
+
+void InitMissingFileHash(void);
 void InitTapeDirectory(char *);
 void InitScoreDirectory(char *);
 void InitScoreCacheDirectory(char *);
+void InitScoreTapeDirectory(char *, int);
+void InitScoreCacheTapeDirectory(char *, int);
 void InitUserLevelDirectory(char *);
 void InitNetworkLevelDirectory(char *);
 void InitLevelSetupDirectory(char *);
@@ -315,6 +329,7 @@ void sortTreeInfoBySortFunction(TreeInfo **,
                                                        const void *));
 void sortTreeInfo(TreeInfo **);
 void freeTreeInfo(TreeInfo *);
+TreeInfo *addTopTreeInfoNode(TreeInfo *);
 
 char *getHomeDir(void);
 char *getPersonalDataDir(void);
@@ -328,12 +343,11 @@ char *getCurrentLevelDir(void);
 char *getNewUserLevelSubdir(void);
 char *getTapeDir(char *);
 
-void createDirectory(char *, char *, int);
+void createDirectory(char *, char *);
 void InitMainUserDataDirectory(void);
 void InitUserDataDirectory(void);
 void SetFilePermissions(char *, int);
 
-char *getCookie(char *);
 void fprintFileHeader(FILE *, char *);
 int getFileVersionFromCookieString(const char *);
 boolean checkCookieString(const char *, const char *);
@@ -353,13 +367,16 @@ SetupFileHash *newSetupFileHash(void);
 void freeSetupFileHash(SetupFileHash *);
 char *getHashEntry(SetupFileHash *, char *);
 void setHashEntry(SetupFileHash *, char *, char *);
-char *removeHashEntry(SetupFileHash *, char *);
+void removeHashEntry(SetupFileHash *, char *);
 SetupFileHash *loadSetupFileHash(char *);
 void setSetupInfo(struct TokenInfo *, int, char *);
 char *getSetupValue(int, void *);
 char *getSetupLine(struct TokenInfo *, char *, int);
 
-unsigned int get_hash_from_key(void *);
+unsigned int get_hash_from_string(void *);
+unsigned int get_hash_from_integer(void *);
+int hash_key_strings_are_equal(void *, void *);
+int hash_key_integers_are_equal(void *, void *);
 
 int GetZipFileTreeType(char *);
 char *ExtractZipFileIntoDirectory(char *, char *, int);
@@ -384,7 +401,9 @@ boolean CreateUserLevelSet(char *, char *, char *, int, boolean);
 
 void UpdateLastPlayedLevels_TreeInfo(void);
 void StoreLastPlayedLevels(TreeInfo *);
+void ForcedStoreLastPlayedLevels(TreeInfo *);
 void RestoreLastPlayedLevels(TreeInfo **);
+boolean CheckLastPlayedLevels(void);
 
 void LoadLevelSetup_LastSeries(void);
 void SaveLevelSetup_LastSeries(void);
index d7ec950435948b44fdb2560c7f26c103ad7904f6..5f497c386c56c6dda9088ecfd87940cd3bcfd36c 100644 (file)
 #define SOUND_VOLUME_LEFT(x)           (stereo_volume[x])
 #define SOUND_VOLUME_RIGHT(x)          (stereo_volume[SOUND_MAX_LEFT2RIGHT-x])
 
-#define SAME_SOUND_NR(x,y)             ((x).nr == (y).nr)
-#define SAME_SOUND_DATA(x,y)           ((x).data_ptr == (y).data_ptr)
+#define SAME_SOUND_NR(x, y)            ((x).nr == (y).nr)
+#define SAME_SOUND_DATA(x, y)          ((x).data_ptr == (y).data_ptr)
 
-#define SOUND_VOLUME_FROM_PERCENT(v,p) ((p) < 0   ? SOUND_MIN_VOLUME : \
+#define SOUND_VOLUME_FROM_PERCENT(v, p)        ((p) < 0   ? SOUND_MIN_VOLUME : \
                                         (p) > 100 ? (v) :              \
                                         (p) * (v) / 100)
 
@@ -59,7 +59,7 @@
 #define SOUND_VOLUME_LOOPS(v)  SOUND_VOLUME_FROM_PERCENT(v, setup.volume_loops)
 #define SOUND_VOLUME_MUSIC(v)  SOUND_VOLUME_FROM_PERCENT(v, setup.volume_music)
 
-#define SETUP_SOUND_VOLUME(v,s)                ((s) & SND_CTRL_MUSIC ?         \
+#define SETUP_SOUND_VOLUME(v, s)       ((s) & SND_CTRL_MUSIC ?         \
                                         SOUND_VOLUME_MUSIC(v) :        \
                                         (s) & SND_CTRL_LOOP ?          \
                                         SOUND_VOLUME_LOOPS(v) :        \
@@ -141,6 +141,15 @@ static MusicInfo *getMusicInfoEntryFromMusicID(int);
 // mixer functions
 // ----------------------------------------------------------------------------
 
+static void Mixer_ChannelFinished(int channel)
+{
+  if (!mixer[channel].active)
+    return;
+
+  mixer[channel].active = FALSE;
+  mixer_active_channels--;
+}
+
 void Mixer_InitChannels(void)
 {
   int i;
@@ -148,6 +157,8 @@ void Mixer_InitChannels(void)
   for (i = 0; i < audio.num_channels; i++)
     mixer[i].active = FALSE;
   mixer_active_channels = 0;
+
+  Mix_ChannelFinished(Mixer_ChannelFinished);
 }
 
 static void Mixer_ResetChannelExpiration(int channel)
@@ -166,8 +177,8 @@ static boolean Mixer_ChannelExpired(int channel)
 
   if (expire_loop_sounds &&
       IS_LOOP(mixer[channel]) && !IS_MUSIC(mixer[channel]) &&
-      DelayReached(&mixer[channel].playing_starttime,
-                  SOUND_LOOP_EXPIRATION_TIME))
+      DelayReachedExt2(&mixer[channel].playing_starttime,
+                      SOUND_LOOP_EXPIRATION_TIME, Counter()))
     return TRUE;
 
   if (!Mix_Playing(channel))
@@ -233,7 +244,7 @@ static void Mixer_PlayMusicChannel(void)
     Mix_VolumeMusic(mixer[audio.music_channel].volume);
     Mix_FadeInMusic(mixer[audio.music_channel].data_ptr, loops, 100);
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
     // playing MIDI music is broken since Windows Vista, as it sets the volume
     // for MIDI music also for all other sounds and music, which cannot be set
     // back to normal unless playing MIDI music again with that desired volume
@@ -247,13 +258,7 @@ static void Mixer_PlayMusicChannel(void)
 
 static void Mixer_StopChannel(int channel)
 {
-  if (!mixer[channel].active)
-    return;
-
   Mix_HaltChannel(channel);
-
-  mixer[channel].active = FALSE;
-  mixer_active_channels--;
 }
 
 static void Mixer_StopMusicChannel(void)
@@ -281,7 +286,7 @@ static void Mixer_FadeMusicChannel(void)
 
   Mix_FadeOutMusic(SOUND_FADING_INTERVAL);
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
   // playing MIDI music is broken since Windows Vista, as it sets the volume
   // for MIDI music also for all other sounds and music, which cannot be set
   // back to normal unless playing MIDI music again with that desired volume
@@ -519,6 +524,17 @@ void StartMixer(void)
       (int)sqrt((float)(SOUND_MAX_LEFT2RIGHT * SOUND_MAX_LEFT2RIGHT - i * i));
 }
 
+boolean isSoundPlaying(int nr)
+{
+  int i;
+
+  for (i = audio.first_sound_channel; i < audio.num_channels; i++)
+    if (mixer[i].active && mixer[i].nr == nr)
+      return TRUE;
+
+  return FALSE;
+}
+
 
 // THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS
 // ============================================================================
@@ -587,11 +603,19 @@ static void *Load_WAV_or_MOD(char *filename)
     return NULL;
 }
 
+static int compareMusicInfo(const void *object1, const void *object2)
+{
+  const MusicInfo *mi1 = *((MusicInfo **)object1);
+  const MusicInfo *mi2 = *((MusicInfo **)object2);
+
+  return strcmp(mi1->source_filename, mi2->source_filename);
+}
+
 static void LoadCustomMusic_NoConf(void)
 {
   static boolean draw_init_text = TRUE;                // only draw at startup
   static char *last_music_directory = NULL;
-  char *music_directory = getCustomMusicDirectory();
+  char *music_directory = getCustomMusicDirectory_NoConf();
   Directory *dir;
   DirectoryEntry *dir_entry;
   int num_music = getMusicListSize();
@@ -609,11 +633,15 @@ static void LoadCustomMusic_NoConf(void)
 
   FreeAllMusic_NoConf();
 
-  if ((dir = openDirectory(music_directory)) == NULL)
+  if (music_directory == NULL)
   {
-    Warn("cannot read music directory '%s'", music_directory);
+    Warn("cannot find music directory with unconfigured music");
 
-    audio.music_available = FALSE;
+    return;
+  }
+  else if ((dir = openDirectory(music_directory)) == NULL)
+  {
+    Warn("cannot read music directory '%s'", music_directory);
 
     return;
   }
@@ -660,6 +688,9 @@ static void LoadCustomMusic_NoConf(void)
 
   closeDirectory(dir);
 
+  // sort music files by filename
+  qsort(Music_NoConf, num_music_noconf, sizeof(MusicInfo *), compareMusicInfo);
+
   draw_init_text = FALSE;
 }
 
@@ -675,6 +706,11 @@ int getMusicListSize(void)
          music_info->num_dynamic_file_list_entries);
 }
 
+int getMusicListSize_NoConf(void)
+{
+  return num_music_noconf;
+}
+
 struct FileInfo *getSoundListEntry(int pos)
 {
   int num_sounds = getSoundListSize();
@@ -741,6 +777,16 @@ static MusicInfo *getMusicInfoEntryFromMusicID(int pos)
   return mus_info[list_pos];
 }
 
+char *getSoundInfoEntryFilename(int pos)
+{
+  SoundInfo *snd_info = getSoundInfoEntryFromSoundID(pos);
+
+  if (snd_info == NULL)
+    return NULL;
+
+  return getBaseNamePtr(snd_info->source_filename);
+}
+
 char *getMusicInfoEntryFilename(int pos)
 {
   MusicInfo *mus_info = getMusicInfoEntryFromMusicID(pos);
@@ -1103,7 +1149,7 @@ static void ReloadCustomMusic(void)
   LoadCustomMusic_NoConf();
 }
 
-void InitReloadCustomSounds(char *set_identifier)
+void InitReloadCustomSounds(void)
 {
   if (!audio.sound_available)
     return;
@@ -1111,7 +1157,7 @@ void InitReloadCustomSounds(char *set_identifier)
   ReloadCustomSounds();
 }
 
-void InitReloadCustomMusic(char *set_identifier)
+void InitReloadCustomMusic(void)
 {
   if (!audio.music_available)
     return;
index a2a6599936b86e56b0ebfeb734a5d5802d5beb63..3e392a599d02fe1e949d866839f195b8d97bdd00 100644 (file)
@@ -17,6 +17,7 @@
 
 // values for platform specific sound initialization
 #define AUDIO_SAMPLE_RATE_22050                22050
+#define AUDIO_SAMPLE_RATE_44100                44100
 
 #define AUDIO_FRAGMENT_SIZE_512                512
 #define AUDIO_FRAGMENT_SIZE_1024       1024
@@ -35,7 +36,7 @@
 
 #define DEFAULT_AUDIO_SAMPLE_RATE      AUDIO_SAMPLE_RATE_22050
 
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
 #define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_1024
 #else
 #define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_512
@@ -101,6 +102,8 @@ void UnixCloseAudio(void);
 void Mixer_InitChannels(void);
 void StartMixer(void);
 
+boolean isSoundPlaying(int);
+
 // sound client functions
 void PlayMusic(int);
 void PlayMusicLoop(int);
@@ -122,8 +125,10 @@ void ExpireSoundLoops(boolean);
 
 int getSoundListSize(void);
 int getMusicListSize(void);
+int getMusicListSize_NoConf(void);
 struct FileInfo *getSoundListEntry(int);
 struct FileInfo *getMusicListEntry(int);
+char *getSoundInfoEntryFilename(int);
 char *getMusicInfoEntryFilename(int);
 char *getCurrentlyPlayingMusicFilename(void);
 int getSoundListPropertyMappingSize(void);
@@ -134,8 +139,8 @@ void InitSoundList(struct ConfigInfo *, int, struct ConfigTypeInfo *,
                   char **, char **, char **, char **, char **);
 void InitMusicList(struct ConfigInfo *, int, struct ConfigTypeInfo *,
                   char **, char **, char **, char **, char **);
-void InitReloadCustomSounds(char *);
-void InitReloadCustomMusic(char *);
+void InitReloadCustomSounds(void);
+void InitReloadCustomMusic(void);
 void FreeAllSounds(void);
 void FreeAllMusic(void);
 
index 64aaf0f822210821d3ba5925808d310db6d027e0..a1f009f77c8470f5d0b7e0fcbe85eb97db53ecd0 100644 (file)
@@ -69,22 +69,23 @@ int                 FrameCounter = 0;
 // init/close functions
 // ============================================================================
 
-void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
-                    char *program_title, char *icon_title,
+void InitProgramInfo(char *command_filename,
+                    char *config_filename, char *userdata_subdir,
+                    char *program_basename, char *program_title,
                     char *icon_filename, char *cookie_prefix,
                     char *program_version_string, int program_version)
 {
-  program.command_basepath = getBasePath(argv0);
-  program.command_basename = getBaseName(argv0);
+  program.command_basepath = getBasePath(command_filename);
+  program.command_basename = getBaseName(command_filename);
 
   program.config_filename = config_filename;
 
   program.userdata_subdir = userdata_subdir;
   program.userdata_path = getMainUserGameDataDir();
 
+  program.program_basename = program_basename;
   program.program_title = program_title;
   program.window_title = "(undefined)";
-  program.icon_title = icon_title;
 
   program.icon_filename = icon_filename;
 
@@ -98,10 +99,10 @@ void InitProgramInfo(char *argv0, char *config_filename, char *userdata_subdir,
 
   program.version_string = program_version_string;
 
-  program.log_filename[LOG_OUT_ID] = getLogFilename(LOG_OUT_BASENAME);
-  program.log_filename[LOG_ERR_ID] = getLogFilename(LOG_ERR_BASENAME);
-  program.log_file[LOG_OUT_ID] = program.log_file_default[LOG_OUT_ID] = stdout;
-  program.log_file[LOG_ERR_ID] = program.log_file_default[LOG_ERR_ID] = stderr;
+  program.log_filename = getLogFilename(getLogBasename(program_basename));
+  program.log_file = program.log_file_default = stdout;
+
+  program.api_thread_count = 0;
 
   program.headless = FALSE;
 }
@@ -120,7 +121,7 @@ void InitNetworkInfo(boolean enabled, boolean connected, boolean serveronly,
   network.is_server_thread = FALSE;
 }
 
-void InitRuntimeInfo()
+void InitRuntimeInfo(void)
 {
 #if defined(HAS_TOUCH_DEVICE)
   runtime.uses_touch_device = TRUE;
@@ -167,7 +168,7 @@ void InitPlatformDependentStuff(void)
   // this is initialized in GetOptions(), but may already be used before
   options.verbose = TRUE;
 
-  OpenLogFiles();
+  OpenLogFile();
 
   int sdl_init_flags = SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE;
 
@@ -179,7 +180,7 @@ void InitPlatformDependentStuff(void)
 
 void ClosePlatformDependentStuff(void)
 {
-  CloseLogFiles();
+  CloseLogFile();
 }
 
 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
@@ -271,7 +272,7 @@ void InitGfxClipRegion(boolean enabled, int x, int y, int width, int height)
   gfx.clip_height = height;
 }
 
-void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void))
+void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean))
 {
   gfx.draw_busy_anim_function = draw_busy_anim_function;
 }
@@ -286,11 +287,16 @@ void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int))
   gfx.draw_global_border_function = draw_global_border_function;
 }
 
-void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int))
+void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int, int))
 {
   gfx.draw_tile_cursor_function = draw_tile_cursor_function;
 }
 
+void InitGfxDrawEnvelopeRequestFunction(void (*draw_envelope_request_function)(int))
+{
+  gfx.draw_envelope_request_function = draw_envelope_request_function;
+}
+
 void InitGfxCustomArtworkInfo(void)
 {
   gfx.override_level_graphics = FALSE;
@@ -447,7 +453,8 @@ void SetDrawBackgroundMask(int draw_background_mask)
   gfx.draw_background_mask = draw_background_mask;
 }
 
-static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
+void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask,
+                        int x, int y, int width, int height)
 {
   if (background_bitmap_tile != NULL)
     gfx.background_bitmap_mask |= mask;
@@ -458,40 +465,19 @@ static void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
     return;
 
   if (mask == REDRAW_ALL)
-    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
+    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
+                   x, y, width, height,
                    0, 0, video.width, video.height);
   else if (mask == REDRAW_FIELD)
-    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
+    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
+                   x, y, width, height,
                    gfx.real_sx, gfx.real_sy, gfx.full_sxsize, gfx.full_sysize);
   else if (mask == REDRAW_DOOR_1)
-    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap, 0, 0, 0, 0,
+    BlitBitmapTiled(background_bitmap_tile, gfx.background_bitmap,
+                   x, y, width, height,
                    gfx.dx, gfx.dy, gfx.dxsize, gfx.dysize);
 }
 
-void SetWindowBackgroundBitmap(Bitmap *background_bitmap_tile)
-{
-  // remove every mask before setting mask for window
-  // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
-  SetBackgroundBitmap(NULL, 0xffff);           // !!! FIX THIS !!!
-  SetBackgroundBitmap(background_bitmap_tile, REDRAW_ALL);
-}
-
-void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
-{
-  // remove window area mask before setting mask for main area
-  // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
-  SetBackgroundBitmap(NULL, REDRAW_ALL);       // !!! FIX THIS !!!
-  SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
-}
-
-void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
-{
-  // remove window area mask before setting mask for door area
-  // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
-  SetBackgroundBitmap(NULL, REDRAW_ALL);       // !!! FIX THIS !!!
-  SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
-}
-
 
 // ============================================================================
 // video functions
@@ -565,14 +551,14 @@ void InitVideoBuffer(int width, int height, int depth, boolean fullscreen)
   video.window_scaling_available = WINDOW_SCALING_STATUS;
 
   video.frame_counter = 0;
-  video.frame_delay = 0;
-  video.frame_delay_value = GAME_FRAME_DELAY;
+  video.frame_delay.count = 0;
+  video.frame_delay.value = GAME_FRAME_DELAY;
 
   video.shifted_up = FALSE;
   video.shifted_up_pos = 0;
   video.shifted_up_pos_last = 0;
-  video.shifted_up_delay = 0;
-  video.shifted_up_delay_value = ONE_SECOND_DELAY / 4;
+  video.shifted_up_delay.count = 0;
+  video.shifted_up_delay.value = ONE_SECOND_DELAY / 4;
 
   SDLInitVideoBuffer(fullscreen);
 
@@ -613,9 +599,22 @@ void FreeBitmap(Bitmap *bitmap)
   free(bitmap);
 }
 
+void ResetBitmapAlpha(Bitmap *bitmap)
+{
+  bitmap->alpha[0][0] = -1;
+  bitmap->alpha[0][1] = -1;
+  bitmap->alpha[1][0] = -1;
+  bitmap->alpha[1][1] = -1;
+  bitmap->alpha_next_blit = -1;
+}
+
 Bitmap *CreateBitmapStruct(void)
 {
-  return checked_calloc(sizeof(Bitmap));
+  Bitmap *new_bitmap = checked_calloc(sizeof(Bitmap));
+
+  ResetBitmapAlpha(new_bitmap);
+
+  return new_bitmap;
 }
 
 Bitmap *CreateBitmap(int width, int height, int depth)
@@ -625,7 +624,7 @@ Bitmap *CreateBitmap(int width, int height, int depth)
   int real_height = MAX(1, height);    // prevent zero bitmap height
   int real_depth  = GetRealDepth(depth);
 
-  SDLCreateBitmapContent(new_bitmap, real_width, real_height, real_depth);
+  new_bitmap->surface = SDLCreateNativeSurface(real_width, real_height, real_depth);
 
   new_bitmap->width  = real_width;
   new_bitmap->height = real_height;
@@ -688,8 +687,7 @@ void SetRedrawMaskFromArea(int x, int y, int width, int height)
     redraw_mask = REDRAW_ALL;
 }
 
-static boolean CheckDrawingArea(int x, int y, int width, int height,
-                               int draw_mask)
+static boolean CheckDrawingArea(int x, int y, int draw_mask)
 {
   if (draw_mask == REDRAW_NONE)
     return FALSE;
@@ -723,15 +721,15 @@ boolean DrawingDeactivatedField(void)
   return FALSE;
 }
 
-boolean DrawingDeactivated(int x, int y, int width, int height)
+boolean DrawingDeactivated(int x, int y)
 {
-  return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
+  return CheckDrawingArea(x, y, gfx.draw_deactivation_mask);
 }
 
 boolean DrawingOnBackground(int x, int y)
 {
-  return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
-         CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
+  return (CheckDrawingArea(x, y, gfx.background_bitmap_mask) &&
+         CheckDrawingArea(x, y, gfx.draw_background_mask));
 }
 
 static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
@@ -787,6 +785,12 @@ static boolean InClippedRectangle(Bitmap *bitmap, int *x, int *y,
   return TRUE;
 }
 
+void SetBitmapAlphaNextBlit(Bitmap *bitmap, int alpha)
+{
+  // set alpha value for next blitting of bitmap
+  bitmap->alpha_next_blit = alpha;
+}
+
 void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                int src_x, int src_y, int width, int height,
                int dst_x, int dst_y)
@@ -800,7 +804,7 @@ void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   if (src_bitmap == NULL || dst_bitmap == NULL)
     return;
 
-  if (DrawingDeactivated(dst_x, dst_y, width, height))
+  if (DrawingDeactivated(dst_x, dst_y))
     return;
 
   if (!InClippedRectangle(src_bitmap, &src_x, &src_y, &width, &height, FALSE) ||
@@ -904,7 +908,10 @@ void FadeRectangle(int x, int y, int width, int height,
 void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
                   Pixel color)
 {
-  if (DrawingDeactivated(x, y, width, height))
+  if (program.headless)
+    return;
+
+  if (DrawingDeactivated(x, y))
     return;
 
   if (!InClippedRectangle(bitmap, &x, &y, &width, &height, TRUE))
@@ -931,7 +938,13 @@ void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
                      int src_x, int src_y, int width, int height,
                      int dst_x, int dst_y)
 {
-  if (DrawingDeactivated(dst_x, dst_y, width, height))
+  if (program.headless)
+    return;
+
+  if (src_bitmap == NULL || dst_bitmap == NULL)
+    return;
+
+  if (DrawingDeactivated(dst_x, dst_y))
     return;
 
   sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
@@ -1007,12 +1020,6 @@ void BlitToScreenMasked(Bitmap *bitmap,
     BlitTextureMasked(bitmap, src_x, src_y, width, height, dst_x, dst_y);
 }
 
-void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
-                        int to_x, int to_y)
-{
-  SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
-}
-
 void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
                         int to_x, int to_y)
 {
@@ -1081,15 +1088,6 @@ Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
 }
 
-Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
-{
-  unsigned int color_r = (color >> 16) & 0xff;
-  unsigned int color_g = (color >>  8) & 0xff;
-  unsigned int color_b = (color >>  0) & 0xff;
-
-  return GetPixelFromRGB(bitmap, color_r, color_g, color_b);
-}
-
 void KeyboardAutoRepeatOn(void)
 {
   keyrepeat_status = TRUE;
@@ -1107,12 +1105,12 @@ boolean SetVideoMode(boolean fullscreen)
 
 void SetVideoFrameDelay(unsigned int frame_delay_value)
 {
-  video.frame_delay_value = frame_delay_value;
+  video.frame_delay.value = frame_delay_value;
 }
 
 unsigned int GetVideoFrameDelay(void)
 {
-  return video.frame_delay_value;
+  return video.frame_delay.value;
 }
 
 boolean ChangeVideoModeIfNeeded(boolean fullscreen)
@@ -1670,6 +1668,8 @@ void OpenAudio(void)
   audio.device_name = NULL;
   audio.device_fd = -1;
 
+  audio.sample_rate = DEFAULT_AUDIO_SAMPLE_RATE;
+
   audio.num_channels = 0;
   audio.music_channel = 0;
   audio.first_sound_channel = 0;
@@ -1728,7 +1728,7 @@ void CheckQuitEvent(void)
     program.exit_function(0);
 }
 
-Key GetEventKey(KeyEvent *event, boolean with_modifiers)
+Key GetEventKey(KeyEvent *event)
 {
   // key up/down events in SDL2 do not return text characters anymore
   return event->keysym.sym;
@@ -1807,7 +1807,7 @@ void StartTextInput(int x, int y, int width, int height)
   if (y + height > SCREEN_KEYBOARD_POS(video.height))
   {
     video.shifted_up_pos = y + height - SCREEN_KEYBOARD_POS(video.height);
-    video.shifted_up_delay = SDL_GetTicks();
+    video.shifted_up_delay.count = SDL_GetTicks();
     video.shifted_up = TRUE;
   }
 #endif
@@ -1823,7 +1823,7 @@ void StopTextInput(void)
   if (video.shifted_up)
   {
     video.shifted_up_pos = 0;
-    video.shifted_up_delay = SDL_GetTicks();
+    video.shifted_up_delay.count = SDL_GetTicks();
     video.shifted_up = FALSE;
   }
 #endif
@@ -1843,6 +1843,24 @@ void PushUserEvent(int code, int value1, int value2)
   SDL_PushEvent((SDL_Event *)&event);
 }
 
+boolean PendingEscapeKeyEvent(void)
+{
+  if (PendingEvent())
+  {
+    Event event;
+
+    // check if any key press event is pending
+    if (SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) != 1)
+      return FALSE;
+
+    // check if pressed key is "Escape" key
+    if (event.key.keysym.sym == KSYM_Escape)
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
 
 // ============================================================================
 // joystick functions
@@ -1888,17 +1906,19 @@ void InitEmscriptenFilesystem(void)
 {
 #if defined(PLATFORM_EMSCRIPTEN)
   EM_ASM
-  (
+  ({
+    dir = UTF8ToString($0);
+
     Module.sync_done = 0;
 
-    FS.mkdir('/persistent');           // create persistent data directory
-    FS.mount(IDBFS, {}, '/persistent');        // mount with IDBFS filesystem type
+    FS.mkdir(dir);                     // create persistent data directory
+    FS.mount(IDBFS, {}, dir);          // mount with IDBFS filesystem type
     FS.syncfs(true, function(err)      // sync persistent data into memory
     {
       assert(!err);
       Module.sync_done = 1;
     });
-  );
+  }, PERSISTENT_DIRECTORY);
 
   // wait for persistent data to be synchronized to memory
   while (emscripten_run_script_int("Module.sync_done") == 0)
index c07ab82298cb38cfe8da9947a6af06041c748da8..dc6d0f363d69f438b6e4c52cbafb2e8a5508eea2 100644 (file)
@@ -16,9 +16,9 @@
 #include "types.h"
 
 
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
 #include "macosx.h"
-#elif defined(PLATFORM_WIN32)
+#elif defined(PLATFORM_WINDOWS)
 #include "windows.h"
 #elif defined(PLATFORM_ANDROID)
 #include "android.h"
 #define API_SERVER_METHOD              "POST"
 #define API_SERVER_URI_ADD             "/api/scores/add"
 #define API_SERVER_URI_GET             "/api/scores/get"
+#define API_SERVER_URI_GETTAPE         "/api/scores/gettape"
 #define API_SERVER_URI_RENAME          "/api/players/rename"
+#define API_SERVER_URI_RESETUUID       "/api/players/resetuuid"
 
 #if defined(TESTING)
 #undef API_SERVER_HOSTNAME
 #define USE_TOUCH_INPUT_OVERLAY
 #define USE_COMPLETE_DISPLAY
 #define HAS_SCREEN_KEYBOARD
-#define SCREEN_KEYBOARD_POS(h)         ((h) / 2)
+#define SCREEN_KEYBOARD_POS(h)         ((h) * 40 / 100)
 #endif
 
 // values for drag-and-drop support (some parts not added before SDL 2.0.5)
 #define DEFAULT_KEY_RIGHT              KSYM_Right
 #define DEFAULT_KEY_UP                 KSYM_Up
 #define DEFAULT_KEY_DOWN               KSYM_Down
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
 #define DEFAULT_KEY_SNAP               KSYM_Control_L
 #define DEFAULT_KEY_DROP               KSYM_KP_Enter
 #else
 // default shortcut keys
 #define DEFAULT_KEY_SAVE_GAME          KSYM_F1
 #define DEFAULT_KEY_LOAD_GAME          KSYM_F2
+#define DEFAULT_KEY_RESTART_GAME       KSYM_F3
+#define DEFAULT_KEY_PAUSE_BEFORE_END   KSYM_F4
 #define DEFAULT_KEY_TOGGLE_PAUSE       KSYM_space
 #define DEFAULT_KEY_FOCUS_PLAYER_1     KSYM_F5
 #define DEFAULT_KEY_FOCUS_PLAYER_2     KSYM_F6
 #define DEFAULT_KEY_SNAP_RIGHT         KSYM_UNDEFINED
 #define DEFAULT_KEY_SNAP_UP            KSYM_UNDEFINED
 #define DEFAULT_KEY_SNAP_DOWN          KSYM_UNDEFINED
+#define DEFAULT_KEY_SPEED_FAST         KSYM_f
+#define DEFAULT_KEY_SPEED_SLOW         KSYM_s
 
 // default debug setup keys and values
 #define DEFAULT_FRAME_DELAY_0          20              // 100 % speed
 #define MB_MENU_MARK                   TRUE
 #define MB_MENU_INITIALIZE             (-1)
 #define MB_MENU_LEAVE                  (-2)
+#define MB_MENU_CONTINUE               (-3)
 #define MB_LEFTBUTTON                  1
 #define MB_MIDDLEBUTTON                        2
 #define MB_RIGHTBUTTON                 3
 // values for drawing stages for global animations
 #define DRAW_GLOBAL_ANIM_STAGE_1       1
 #define DRAW_GLOBAL_ANIM_STAGE_2       2
+#define DRAW_GLOBAL_ANIM_STAGE_3       3
+#define DRAW_GLOBAL_ANIM_STAGE_RESTART 4
 
 // values for drawing target (various functions)
 #define DRAW_TO_BACKBUFFER             0
 #define DRAW_TO_FADE_TARGET            4
 
 // values for move directions and special "button" key bitmasks
-#define MV_NONE                        0
-#define MV_LEFT                        (1 << MV_BIT_LEFT)
-#define MV_RIGHT               (1 << MV_BIT_RIGHT)
-#define MV_UP                  (1 << MV_BIT_UP)
-#define MV_DOWN                        (1 << MV_BIT_DOWN)
-
-#define MV_UPLEFT              (MV_UP   | MV_LEFT)
-#define MV_UPRIGHT             (MV_UP   | MV_RIGHT)
-#define MV_DOWNLEFT            (MV_DOWN | MV_LEFT)
-#define MV_DOWNRIGHT           (MV_DOWN | MV_RIGHT)
-
-#define MV_HORIZONTAL          (MV_LEFT | MV_RIGHT)
-#define MV_VERTICAL            (MV_UP   | MV_DOWN)
-#define MV_ALL_DIRECTIONS      (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)
-#define MV_ANY_DIRECTION       (MV_ALL_DIRECTIONS)
-#define MV_NO_DIRECTION                (MV_NONE)
-
-#define KEY_BUTTON_1           (1 << BUTTON_1)
-#define KEY_BUTTON_2           (1 << BUTTON_2)
-#define KEY_BUTTON_SNAP                KEY_BUTTON_1
-#define KEY_BUTTON_DROP                KEY_BUTTON_2
-#define KEY_MOTION             (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)
-#define KEY_BUTTON             (KEY_BUTTON_1 | KEY_BUTTON_2)
-#define KEY_ACTION             (KEY_MOTION | KEY_BUTTON)
-
-#define KEY_SET_FOCUS          (1 << BIT_SET_FOCUS)
-
-#define MV_DIR_FROM_BIT(x)     ((x) < NUM_DIRECTIONS ? 1 << (x) :        \
-                                (x) == MV_BIT_UPLEFT    ? MV_UPLEFT    : \
-                                (x) == MV_BIT_UPRIGHT   ? MV_UPRIGHT   : \
-                                (x) == MV_BIT_DOWNLEFT  ? MV_DOWNLEFT  : \
-                                (x) == MV_BIT_DOWNRIGHT ? MV_DOWNRIGHT : \
-                                MV_NONE)
-
-#define MV_DIR_TO_BIT(x)       ((x) == MV_LEFT      ? MV_BIT_LEFT      : \
-                                (x) == MV_RIGHT     ? MV_BIT_RIGHT     : \
-                                (x) == MV_UP        ? MV_BIT_UP        : \
-                                (x) == MV_DOWN      ? MV_BIT_DOWN      : \
-                                (x) == MV_UPLEFT    ? MV_BIT_UPLEFT    : \
-                                (x) == MV_UPRIGHT   ? MV_BIT_UPRIGHT   : \
-                                (x) == MV_DOWNLEFT  ? MV_BIT_DOWNLEFT  : \
-                                (x) == MV_DOWNRIGHT ? MV_BIT_DOWNRIGHT : \
-                                MV_BIT_DOWN)
-
-#define MV_DIR_OPPOSITE(x)     ((x) == MV_LEFT      ? MV_RIGHT     : \
-                                (x) == MV_RIGHT     ? MV_LEFT      : \
-                                (x) == MV_UP        ? MV_DOWN      : \
-                                (x) == MV_DOWN      ? MV_UP        : \
-                                (x) == MV_UPLEFT    ? MV_DOWNRIGHT : \
-                                (x) == MV_UPRIGHT   ? MV_DOWNLEFT  : \
-                                (x) == MV_DOWNLEFT  ? MV_UPRIGHT   : \
-                                (x) == MV_DOWNRIGHT ? MV_UPLEFT    : \
-                                MV_NONE)
+#define MV_NONE                                0
+#define MV_LEFT                                (1 << MV_BIT_LEFT)
+#define MV_RIGHT                       (1 << MV_BIT_RIGHT)
+#define MV_UP                          (1 << MV_BIT_UP)
+#define MV_DOWN                                (1 << MV_BIT_DOWN)
+
+#define MV_UPLEFT                      (MV_UP   | MV_LEFT)
+#define MV_UPRIGHT                     (MV_UP   | MV_RIGHT)
+#define MV_DOWNLEFT                    (MV_DOWN | MV_LEFT)
+#define MV_DOWNRIGHT                   (MV_DOWN | MV_RIGHT)
+
+#define MV_HORIZONTAL                  (MV_LEFT | MV_RIGHT)
+#define MV_VERTICAL                    (MV_UP   | MV_DOWN)
+#define MV_ALL_DIRECTIONS              (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)
+#define MV_ANY_DIRECTION               (MV_ALL_DIRECTIONS)
+#define MV_NO_DIRECTION                        (MV_NONE)
+
+#define KEY_BUTTON_1                   (1 << BUTTON_1)
+#define KEY_BUTTON_2                   (1 << BUTTON_2)
+#define KEY_BUTTON_SNAP                        KEY_BUTTON_1
+#define KEY_BUTTON_DROP                        KEY_BUTTON_2
+#define KEY_MOTION                     (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)
+#define KEY_BUTTON                     (KEY_BUTTON_1 | KEY_BUTTON_2)
+#define KEY_ACTION                     (KEY_MOTION | KEY_BUTTON)
+
+#define KEY_SET_FOCUS                  (1 << BIT_SET_FOCUS)
+
+#define MV_DIR_FROM_BIT(x)             ((x) < NUM_DIRECTIONS ? 1 << (x) :        \
+                                        (x) == MV_BIT_UPLEFT    ? MV_UPLEFT    : \
+                                        (x) == MV_BIT_UPRIGHT   ? MV_UPRIGHT   : \
+                                        (x) == MV_BIT_DOWNLEFT  ? MV_DOWNLEFT  : \
+                                        (x) == MV_BIT_DOWNRIGHT ? MV_DOWNRIGHT : \
+                                        MV_NONE)
+
+#define MV_DIR_TO_BIT(x)               ((x) == MV_LEFT      ? MV_BIT_LEFT      : \
+                                        (x) == MV_RIGHT     ? MV_BIT_RIGHT     : \
+                                        (x) == MV_UP        ? MV_BIT_UP        : \
+                                        (x) == MV_DOWN      ? MV_BIT_DOWN      : \
+                                        (x) == MV_UPLEFT    ? MV_BIT_UPLEFT    : \
+                                        (x) == MV_UPRIGHT   ? MV_BIT_UPRIGHT   : \
+                                        (x) == MV_DOWNLEFT  ? MV_BIT_DOWNLEFT  : \
+                                        (x) == MV_DOWNRIGHT ? MV_BIT_DOWNRIGHT : \
+                                        MV_BIT_DOWN)
+
+#define MV_DIR_OPPOSITE(x)             ((x) == MV_LEFT      ? MV_RIGHT     : \
+                                        (x) == MV_RIGHT     ? MV_LEFT      : \
+                                        (x) == MV_UP        ? MV_DOWN      : \
+                                        (x) == MV_DOWN      ? MV_UP        : \
+                                        (x) == MV_UPLEFT    ? MV_DOWNRIGHT : \
+                                        (x) == MV_UPRIGHT   ? MV_DOWNLEFT  : \
+                                        (x) == MV_DOWNLEFT  ? MV_UPRIGHT   : \
+                                        (x) == MV_DOWNRIGHT ? MV_UPLEFT    : \
+                                        MV_NONE)
 
 // values for animation mode (frame order and direction)
 // (stored in level files -- never change existing values)
-#define ANIM_NONE              0
-#define ANIM_LOOP              (1 << 0)
-#define ANIM_LINEAR            (1 << 1)
-#define ANIM_PINGPONG          (1 << 2)
-#define ANIM_PINGPONG2         (1 << 3)
-#define ANIM_RANDOM            (1 << 4)
-#define ANIM_CE_VALUE          (1 << 5)
-#define ANIM_CE_SCORE          (1 << 6)
-#define ANIM_CE_DELAY          (1 << 7)
-#define ANIM_REVERSE           (1 << 8)
-#define ANIM_OPAQUE_PLAYER     (1 << 9)
+#define ANIM_NONE                      0
+#define ANIM_LOOP                      (1 << 0)
+#define ANIM_LINEAR                    (1 << 1)
+#define ANIM_PINGPONG                  (1 << 2)
+#define ANIM_PINGPONG2                 (1 << 3)
+#define ANIM_RANDOM                    (1 << 4)
+#define ANIM_CE_VALUE                  (1 << 5)
+#define ANIM_CE_SCORE                  (1 << 6)
+#define ANIM_CE_DELAY                  (1 << 7)
+#define ANIM_REVERSE                   (1 << 8)
+#define ANIM_OPAQUE_PLAYER             (1 << 9)
+#define ANIM_LEVEL_NR                  (1 << 10)
 
 // values for special (non game element) animation modes
 // (not stored in level files -- can be changed, if needed)
-#define ANIM_HORIZONTAL                (1 << 10)
-#define ANIM_VERTICAL          (1 << 11)
-#define ANIM_CENTERED          (1 << 12)
-#define ANIM_STATIC_PANEL      (1 << 13)
-#define ANIM_ALL               (1 << 14)
-#define ANIM_ONCE              (1 << 15)
+#define ANIM_HORIZONTAL                        (1 << 11)
+#define ANIM_VERTICAL                  (1 << 12)
+#define ANIM_CENTERED                  (1 << 13)
+#define ANIM_STATIC_PANEL              (1 << 14)
+#define ANIM_ALL                       (1 << 15)
+#define ANIM_ONCE                      (1 << 16)
+#define ANIM_TILED                     (1 << 17)
+#define ANIM_RANDOM_STATIC             (1 << 18)
 
-#define ANIM_DEFAULT           ANIM_LOOP
+#define ANIM_DEFAULT                   ANIM_LOOP
 
-// values for special drawing styles and event handling
-#define STYLE_NONE             0
+// values for special global animation events
+#define ANIM_EVENT_UNDEFINED           -1
+#define ANIM_EVENT_NONE                        0
+#define ANIM_EVENT_SELF                        (1 << 0)
+#define ANIM_EVENT_ANY                 (1 << 1)
+#define ANIM_EVENT_CLICK               (1 << 2)
+#define ANIM_EVENT_INIT                        (1 << 3)
+#define ANIM_EVENT_START               (1 << 4)
+#define ANIM_EVENT_END                 (1 << 5)
+#define ANIM_EVENT_POST                        (1 << 6)
+#define ANIM_EVENT_UNCLICK_ANY         (1 << 7)
+#define ANIM_EVENT_CE_CHANGE           (1 << 8)
+
+// event mask:  bits 0-15
+// CE number:   bits 16-23
+// anim number: bits 16-23
+// page number: bits 24-31
+// part number: bits 24-31
+#define ANIM_EVENT_CE_BIT              16
+#define ANIM_EVENT_ANIM_BIT            16
+#define ANIM_EVENT_PAGE_BIT            24
+#define ANIM_EVENT_PART_BIT            24
+
+#define ANIM_EVENT_CE_MASK             (0xff << ANIM_EVENT_CE_BIT)
+#define ANIM_EVENT_ANIM_MASK           (0xff << ANIM_EVENT_ANIM_BIT)
+#define ANIM_EVENT_PAGE_MASK           (0xff << ANIM_EVENT_PAGE_BIT)
+#define ANIM_EVENT_PART_MASK           (0xff << ANIM_EVENT_PART_BIT)
+
+#define ANIM_EVENT_DEFAULT             ANIM_EVENT_NONE
 
-// values used for crumbled graphics
-#define STYLE_ACCURATE_BORDERS (1 << 0)
-#define STYLE_INNER_CORNERS    (1 << 1)
+// values for special global animation event actions
+#define ANIM_EVENT_ACTION_NONE         -1
 
-// values used for game panel graphics
-#define STYLE_REVERSE          (1 << 2)
-#define STYLE_LEFTMOST_POSITION        (1 << 3)
+// values for special global animation delay types
+#define ANIM_DELAY_UNDEFINED           -1
+#define ANIM_DELAY_NONE                        0
+#define ANIM_DELAY_INIT                        1
+#define ANIM_DELAY_ANIM                        2
+#define ANIM_DELAY_POST                        3
 
-// values used for global animations
-#define STYLE_BLOCK            (1 << 4)
-#define STYLE_PASSTHROUGH      (1 << 5)
-#define STYLE_MULTIPLE_ACTIONS (1 << 6)
+// values for special global animation delay actions
+#define ANIM_DELAY_ACTION_NONE         -1
 
-#define STYLE_DEFAULT          STYLE_NONE
+// values for special drawing styles and event handling
+#define STYLE_NONE                     0
 
-// values for special global animation delay types
-#define ANIM_DELAY_UNDEFINED   -1
-#define ANIM_DELAY_NONE                0
-#define ANIM_DELAY_INIT                1
-#define ANIM_DELAY_ANIM                2
-#define ANIM_DELAY_POST                3
+// values used for crumbled graphics
+#define STYLE_ACCURATE_BORDERS         (1 << 0)
+#define STYLE_INNER_CORNERS            (1 << 1)
 
-// values for special global animation delay actions
-#define ANIM_DELAY_ACTION_NONE -1
+// values used for game panel graphics
+#define STYLE_REVERSE                  (1 << 2)
+#define STYLE_LEFTMOST_POSITION                (1 << 3)
 
-// values for special global animation events
-#define ANIM_EVENT_UNDEFINED   -1
-#define ANIM_EVENT_NONE                0
-#define ANIM_EVENT_SELF                (1 << 16)
-#define ANIM_EVENT_ANY         (1 << 17)
-#define ANIM_EVENT_CLICK       (1 << 18)
-#define ANIM_EVENT_INIT                (1 << 19)
-#define ANIM_EVENT_START       (1 << 20)
-#define ANIM_EVENT_END         (1 << 21)
-#define ANIM_EVENT_POST                (1 << 22)
-#define ANIM_EVENT_UNCLICK_ANY (1 << 23)
-
-// anim number: bits 0-7
-// part number: bits 8-15
-#define ANIM_EVENT_ANIM_BIT    0
-#define ANIM_EVENT_PART_BIT    8
-
-#define ANIM_EVENT_ANIM_MASK   (0xff << ANIM_EVENT_ANIM_BIT)
-#define ANIM_EVENT_PART_MASK   (0xff << ANIM_EVENT_PART_BIT)
-
-#define ANIM_EVENT_DEFAULT     ANIM_EVENT_NONE
+// values used for global animations
+#define STYLE_BLOCK                    (1 << 4)
+#define STYLE_PASSTHROUGH              (1 << 5)
+#define STYLE_MULTIPLE_ACTIONS         (1 << 6)
+#define STYLE_CONSUME_CE_EVENT         (1 << 7)
 
-// values for special global animation event actions
-#define ANIM_EVENT_ACTION_NONE -1
+#define STYLE_DEFAULT                  STYLE_NONE
 
 // values for fade mode
-#define FADE_TYPE_NONE         0
-#define FADE_TYPE_FADE_IN      (1 << 0)
-#define FADE_TYPE_FADE_OUT     (1 << 1)
-#define FADE_TYPE_TRANSFORM    (1 << 2)
-#define FADE_TYPE_CROSSFADE    (1 << 3)
-#define FADE_TYPE_MELT         (1 << 4)
-#define FADE_TYPE_CURTAIN      (1 << 5)
-#define FADE_TYPE_SKIP         (1 << 6)
-
-#define FADE_MODE_NONE         (FADE_TYPE_NONE)
-#define FADE_MODE_FADE_IN      (FADE_TYPE_FADE_IN)
-#define FADE_MODE_FADE_OUT     (FADE_TYPE_FADE_OUT)
-#define FADE_MODE_FADE         (FADE_TYPE_FADE_IN | FADE_TYPE_FADE_OUT)
-#define FADE_MODE_TRANSFORM    (FADE_TYPE_TRANSFORM | FADE_TYPE_FADE_IN)
-#define FADE_MODE_CROSSFADE    (FADE_MODE_TRANSFORM | FADE_TYPE_CROSSFADE)
-#define FADE_MODE_MELT         (FADE_MODE_TRANSFORM | FADE_TYPE_MELT)
-#define FADE_MODE_CURTAIN      (FADE_MODE_TRANSFORM | FADE_TYPE_CURTAIN)
-#define FADE_MODE_SKIP_FADE_IN (FADE_TYPE_SKIP | FADE_TYPE_FADE_IN)
-#define FADE_MODE_SKIP_FADE_OUT        (FADE_TYPE_SKIP | FADE_TYPE_FADE_OUT)
-
-#define FADE_MODE_DEFAULT      FADE_MODE_FADE
-
-#define AUTO_DELAY_UNIT_MS     0
-#define AUTO_DELAY_UNIT_FRAMES 1
-
-#define AUTO_DELAY_UNIT_DEFAULT        AUTO_DELAY_UNIT_MS
+#define FADE_TYPE_NONE                 0
+#define FADE_TYPE_FADE_IN              (1 << 0)
+#define FADE_TYPE_FADE_OUT             (1 << 1)
+#define FADE_TYPE_TRANSFORM            (1 << 2)
+#define FADE_TYPE_CROSSFADE            (1 << 3)
+#define FADE_TYPE_MELT                 (1 << 4)
+#define FADE_TYPE_CURTAIN              (1 << 5)
+#define FADE_TYPE_SKIP                 (1 << 6)
+
+#define FADE_MODE_NONE                 (FADE_TYPE_NONE)
+#define FADE_MODE_FADE_IN              (FADE_TYPE_FADE_IN)
+#define FADE_MODE_FADE_OUT             (FADE_TYPE_FADE_OUT)
+#define FADE_MODE_FADE                 (FADE_TYPE_FADE_IN | FADE_TYPE_FADE_OUT)
+#define FADE_MODE_TRANSFORM            (FADE_TYPE_TRANSFORM | FADE_TYPE_FADE_IN)
+#define FADE_MODE_CROSSFADE            (FADE_MODE_TRANSFORM | FADE_TYPE_CROSSFADE)
+#define FADE_MODE_MELT                 (FADE_MODE_TRANSFORM | FADE_TYPE_MELT)
+#define FADE_MODE_CURTAIN              (FADE_MODE_TRANSFORM | FADE_TYPE_CURTAIN)
+#define FADE_MODE_SKIP_FADE_IN         (FADE_TYPE_SKIP | FADE_TYPE_FADE_IN)
+#define FADE_MODE_SKIP_FADE_OUT                (FADE_TYPE_SKIP | FADE_TYPE_FADE_OUT)
+
+#define FADE_MODE_DEFAULT              FADE_MODE_FADE
+
+#define AUTO_DELAY_UNIT_MS             0
+#define AUTO_DELAY_UNIT_FRAMES         1
+
+#define AUTO_DELAY_UNIT_DEFAULT                AUTO_DELAY_UNIT_MS
 
 // values for toon positions
-#define POS_UNDEFINED          -1
-#define POS_LEFT               0
-#define POS_RIGHT              1
-#define POS_TOP                        2
-#define POS_UPPER              3
-#define POS_MIDDLE             4
-#define POS_LOWER              5
-#define POS_BOTTOM             6
-#define POS_ANY                        7
-#define POS_LAST               8
+#define POS_UNDEFINED                  -1
+#define POS_LEFT                       0
+#define POS_RIGHT                      1
+#define POS_TOP                                2
+#define POS_UPPER                      3
+#define POS_MIDDLE                     4
+#define POS_LOWER                      5
+#define POS_BOTTOM                     6
+#define POS_ANY                                7
+#define POS_CE                         8
+#define POS_CE_TRIGGER                 9
+#define POS_LAST                       10
 
 // values for text alignment
-#define ALIGN_LEFT             (1 << 0)
-#define ALIGN_RIGHT            (1 << 1)
-#define ALIGN_CENTER           (1 << 2)
-#define ALIGN_DEFAULT          ALIGN_LEFT
-
-#define VALIGN_TOP             (1 << 0)
-#define VALIGN_BOTTOM          (1 << 1)
-#define VALIGN_MIDDLE          (1 << 2)
-#define VALIGN_DEFAULT         VALIGN_TOP
-
-#define ALIGNED_XPOS(x,w,a)    ((a) == ALIGN_CENTER  ? (x) - (w) / 2 : \
-                                (a) == ALIGN_RIGHT   ? (x) - (w) : (x))
-#define ALIGNED_YPOS(y,h,v)    ((v) == VALIGN_MIDDLE ? (y) - (h) / 2 : \
-                                (v) == VALIGN_BOTTOM ? (y) - (h) : (y))
-#define ALIGNED_TEXT_XPOS(p)   ALIGNED_XPOS((p)->x, (p)->width,  (p)->align)
-#define ALIGNED_TEXT_YPOS(p)   ALIGNED_YPOS((p)->y, (p)->height, (p)->valign)
-#define ALIGNED_VP_XPOS(p)     ALIGNED_TEXT_XPOS(p)
-#define ALIGNED_VP_YPOS(p)     ALIGNED_TEXT_YPOS(p)
+#define ALIGN_LEFT                     (1 << 0)
+#define ALIGN_RIGHT                    (1 << 1)
+#define ALIGN_CENTER                   (1 << 2)
+#define ALIGN_DEFAULT                  ALIGN_LEFT
+
+#define VALIGN_TOP                     (1 << 0)
+#define VALIGN_BOTTOM                  (1 << 1)
+#define VALIGN_MIDDLE                  (1 << 2)
+#define VALIGN_DEFAULT                 VALIGN_TOP
+
+#define ALIGNED_XPOS(x, w, a)          ((a) == ALIGN_CENTER  ? (x) - (w) / 2 : \
+                                        (a) == ALIGN_RIGHT   ? (x) - (w) : (x))
+#define ALIGNED_YPOS(y, h, v)          ((v) == VALIGN_MIDDLE ? (y) - (h) / 2 : \
+                                        (v) == VALIGN_BOTTOM ? (y) - (h) : (y))
+#define ALIGNED_TEXT_XPOS(p)           ALIGNED_XPOS((p)->x, (p)->width,  (p)->align)
+#define ALIGNED_TEXT_YPOS(p)           ALIGNED_YPOS((p)->y, (p)->height, (p)->valign)
+#define ALIGNED_VP_XPOS(p)             ALIGNED_TEXT_XPOS(p)
+#define ALIGNED_VP_YPOS(p)             ALIGNED_TEXT_YPOS(p)
 
 // values for redraw_mask
-#define REDRAW_NONE            (0)
-#define REDRAW_ALL             (1 << 0)
-#define REDRAW_FIELD           (1 << 1)
-#define REDRAW_DOOR_1          (1 << 2)
-#define REDRAW_DOOR_2          (1 << 3)
-#define REDRAW_DOOR_3          (1 << 4)
-#define REDRAW_FPS             (1 << 5)
-
-#define REDRAW_DOORS           (REDRAW_DOOR_1 | \
-                                REDRAW_DOOR_2 | \
-                                REDRAW_DOOR_3)
-
-#define IN_GFX_FIELD_PLAY(x, y)        (x >= gfx.sx && x < gfx.sx + gfx.sxsize && \
-                                y >= gfx.sy && y < gfx.sy + gfx.sysize)
-#define IN_GFX_FIELD_FULL(x, y)        (x >= gfx.real_sx && \
-                                x <  gfx.real_sx + gfx.full_sxsize && \
-                                y >= gfx.real_sy && \
-                                y <  gfx.real_sy + gfx.full_sysize)
-#define IN_GFX_DOOR_1(x, y)    (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \
-                                y >= gfx.dy && y < gfx.dy + gfx.dysize)
-#define IN_GFX_DOOR_2(x, y)    (x >= gfx.vx && x < gfx.vx + gfx.vxsize && \
-                                y >= gfx.vy && y < gfx.vy + gfx.vysize)
-#define IN_GFX_DOOR_3(x, y)    (x >= gfx.ex && x < gfx.ex + gfx.exsize && \
-                                y >= gfx.ey && y < gfx.ey + gfx.eysize)
+#define REDRAW_NONE                    (0)
+#define REDRAW_ALL                     (1 << 0)
+#define REDRAW_FIELD                   (1 << 1)
+#define REDRAW_DOOR_1                  (1 << 2)
+#define REDRAW_DOOR_2                  (1 << 3)
+#define REDRAW_DOOR_3                  (1 << 4)
+#define REDRAW_FPS                     (1 << 5)
+
+#define REDRAW_DOORS                   (REDRAW_DOOR_1 | \
+                                        REDRAW_DOOR_2 | \
+                                        REDRAW_DOOR_3)
+
+#define IN_GFX_FIELD_PLAY(x, y)                (x >= gfx.sx && x < gfx.sx + gfx.sxsize && \
+                                        y >= gfx.sy && y < gfx.sy + gfx.sysize)
+#define IN_GFX_FIELD_FULL(x, y)                (x >= gfx.real_sx && \
+                                        x <  gfx.real_sx + gfx.full_sxsize && \
+                                        y >= gfx.real_sy && \
+                                        y <  gfx.real_sy + gfx.full_sysize)
+#define IN_GFX_DOOR_1(x, y)            (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \
+                                        y >= gfx.dy && y < gfx.dy + gfx.dysize)
+#define IN_GFX_DOOR_2(x, y)            (x >= gfx.vx && x < gfx.vx + gfx.vxsize && \
+                                        y >= gfx.vy && y < gfx.vy + gfx.vysize)
+#define IN_GFX_DOOR_3(x, y)            (x >= gfx.ex && x < gfx.ex + gfx.exsize && \
+                                        y >= gfx.ey && y < gfx.ey + gfx.eysize)
 
 // values for mouse cursor
-#define CURSOR_UNDEFINED       -1
-#define CURSOR_DEFAULT         0
-#define CURSOR_NONE            1
-#define CURSOR_PLAYFIELD       2
+#define CURSOR_UNDEFINED               -1
+#define CURSOR_DEFAULT                 0
+#define CURSOR_NONE                    1
+#define CURSOR_PLAYFIELD               2
 
 // fundamental game speed values
-#define ONE_SECOND_DELAY       1000    // delay value for one second
-#define MENU_FRAME_DELAY       20      // frame delay in milliseconds
-#define GAME_FRAME_DELAY       20      // frame delay in milliseconds
-#define FFWD_FRAME_DELAY       10      // 200% speed for fast forward
-#define MIN_VSYNC_FRAME_DELAY  15      // minimum value for vsync to keep
-#define MAX_VSYNC_FRAME_DELAY  16      // maximum value for vsync to work
-#define FRAMES_PER_SECOND      (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
-#define FRAMES_PER_SECOND_SP   35
+#define ONE_SECOND_DELAY               1000    // delay value for one second
+#define MENU_FRAME_DELAY               20      // frame delay in milliseconds
+#define GAME_FRAME_DELAY               20      // frame delay in milliseconds
+#define FFWD_FRAME_DELAY               10      // 200% speed for fast forward
+#define MIN_VSYNC_FRAME_DELAY          15      // minimum value for vsync to keep
+#define MAX_VSYNC_FRAME_DELAY          16      // maximum value for vsync to work
+#define FRAMES_PER_SECOND              (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
+#define FRAMES_PER_SECOND_SP           35
+#define FRAMES_PER_SECOND_PAL          50
+#define FRAMES_PER_SECOND_NTSC         60
 
 // maximum playfield size supported by libgame functions
-#define MAX_PLAYFIELD_WIDTH    128
-#define MAX_PLAYFIELD_HEIGHT   128
+#define MAX_PLAYFIELD_WIDTH            128
+#define MAX_PLAYFIELD_HEIGHT           128
 
 // maximum number of parallel players supported by libgame functions
-#define MAX_PLAYERS            4
+#define MAX_PLAYERS                    4
 
 // maximum number of player names
-#define MAX_PLAYER_NAMES       12
+#define MAX_PLAYER_NAMES               12
 
 // maximum allowed length of player name
-#define MAX_PLAYER_NAME_LEN    10
+#define MAX_PLAYER_NAME_LEN            10
 
 // maximum number of levels in a level set
-#define MAX_LEVELS             1000
+#define MAX_LEVELS                     1000
 
 // maximum number of global animation and parts
 #define MAX_GLOBAL_ANIMS               32
                                         JOY_NO_ACTION)
 
 // maximum number of level sets in the level set history
-#define MAX_LEVELDIR_HISTORY   12
+#define MAX_LEVELDIR_HISTORY           100
 
 // default name for empty highscore entry
-#define EMPTY_PLAYER_NAME      "no name"
+#define EMPTY_PLAYER_NAME              "no name"
 
 // default name for unknown player names
-#define ANONYMOUS_NAME         "anonymous"
+#define ANONYMOUS_NAME                 "anonymous"
 
 // default for other unknown names
-#define UNKNOWN_NAME           "unknown"
+#define UNKNOWN_NAME                   "unknown"
 
 // default name for new levels
-#define NAMELESS_LEVEL_NAME    "nameless level"
+#define NAMELESS_LEVEL_NAME            "nameless level"
 
 // default text for non-existant artwork
-#define NOT_AVAILABLE          "(not available)"
+#define NOT_AVAILABLE                  "(not available)"
 
 // default value for undefined filename
-#define UNDEFINED_FILENAME     "[NONE]"
+#define UNDEFINED_FILENAME             "[NONE]"
 
 // default value for undefined levelset
-#define UNDEFINED_LEVELSET     "[NONE]"
+#define UNDEFINED_LEVELSET             "[NONE]"
 
 // default value for undefined password
-#define UNDEFINED_PASSWORD     "[undefined]"
+#define UNDEFINED_PASSWORD             "[undefined]"
+
+// default value for undefined string parameter
+#define ARG_UNDEFINED_STRING           "[undefined]"
 
-// default value for undefined parameter
-#define ARG_DEFAULT            "[DEFAULT]"
+// default value for default string parameter
+#define ARG_DEFAULT                    "[DEFAULT]"
 
-// default values for undefined configuration file parameters
-#define ARG_UNDEFINED          "-1000000"
-#define ARG_UNDEFINED_VALUE    (-1000000)
+// default values for undefined numerical parameter (as string and integer)
+#define ARG_UNDEFINED                  "-1000000"
+#define ARG_UNDEFINED_VALUE            (-1000000)
 
 // default value for off-screen positions
-#define POS_OFFSCREEN          (-1000000)
+#define POS_OFFSCREEN                  (-1000000)
 
 // definitions for game base path and sub-directories
 #ifndef BASE_PATH
-#define BASE_PATH              "."
+#define BASE_PATH                      "."
 #endif
 
 // directory names
-#define GRAPHICS_DIRECTORY     "graphics"
-#define SOUNDS_DIRECTORY       "sounds"
-#define MUSIC_DIRECTORY                "music"
-#define LEVELS_DIRECTORY       "levels"
-#define TAPES_DIRECTORY                "tapes"
-#define SCORES_DIRECTORY       "scores"
-#define DOCS_DIRECTORY         "docs"
-#define CACHE_DIRECTORY                "cache"
-#define CONF_DIRECTORY         "conf"
-#define NETWORK_DIRECTORY      "network"
-#define USERS_DIRECTORY                "users"
-
-#define GFX_CLASSIC_SUBDIR     "gfx_classic"
-#define SND_CLASSIC_SUBDIR     "snd_classic"
-#define MUS_CLASSIC_SUBDIR     "mus_classic"
-
-#define GFX_DEFAULT_SUBDIR     (setup.internal.default_graphics_set)
-#define SND_DEFAULT_SUBDIR     (setup.internal.default_sounds_set)
-#define MUS_DEFAULT_SUBDIR     (setup.internal.default_music_set)
-
-#define GFX_FALLBACK_FILENAME  (setup.internal.fallback_graphics_file)
-#define SND_FALLBACK_FILENAME  (setup.internal.fallback_sounds_file)
-#define MUS_FALLBACK_FILENAME  (setup.internal.fallback_music_file)
-
-#define DEFAULT_LEVELSET       (setup.internal.default_level_series)
+#define GRAPHICS_DIRECTORY             "graphics"
+#define SOUNDS_DIRECTORY               "sounds"
+#define MUSIC_DIRECTORY                        "music"
+#define LEVELS_DIRECTORY               "levels"
+#define TAPES_DIRECTORY                        "tapes"
+#define SCORES_DIRECTORY               "scores"
+#define DOCS_DIRECTORY                 "docs"
+#define ELEMENTS_DIRECTORY             "elements"
+#define CREDITS_DIRECTORY              "credits"
+#define PROGRAM_INFO_DIRECTORY         "program"
+#define LEVELSET_INFO_DIRECTORY                "levelset"
+#define CACHE_DIRECTORY                        "cache"
+#define CONF_DIRECTORY                 "conf"
+#define NETWORK_DIRECTORY              "network"
+#define USERS_DIRECTORY                        "users"
+#define PERSISTENT_DIRECTORY           "/persistent"
+
+#define GFX_CLASSIC_SUBDIR             "gfx_classic"
+#define SND_CLASSIC_SUBDIR             "snd_classic"
+#define MUS_CLASSIC_SUBDIR             "mus_classic"
+
+#define GFX_DEFAULT_SUBDIR             (setup.internal.default_graphics_set)
+#define SND_DEFAULT_SUBDIR             (setup.internal.default_sounds_set)
+#define MUS_DEFAULT_SUBDIR             (setup.internal.default_music_set)
+
+#define GFX_FALLBACK_FILENAME          (setup.internal.fallback_graphics_file)
+#define SND_FALLBACK_FILENAME          (setup.internal.fallback_sounds_file)
+#define MUS_FALLBACK_FILENAME          (setup.internal.fallback_music_file)
+
+#define DEFAULT_LEVELSET               (setup.internal.default_level_series)
 
 // file names and filename extensions
-#define LEVELSETUP_DIRECTORY   "levelsetup"
-#define SETUP_FILENAME         "setup.conf"
-#define USERSETUP_FILENAME     "usersetup.conf"
-#define AUTOSETUP_FILENAME     "autosetup.conf"
-#define LEVELSETUP_FILENAME    "levelsetup.conf"
-#define SERVERSETUP_FILENAME   "serversetup.conf"
-#define EDITORSETUP_FILENAME   "editorsetup.conf"
-#define EDITORCASCADE_FILENAME "editorcascade.conf"
-#define HELPANIM_FILENAME      "helpanim.conf"
-#define HELPTEXT_FILENAME      "helptext.conf"
-#define LEVELINFO_FILENAME     "levelinfo.conf"
-#define GRAPHICSINFO_FILENAME  "graphicsinfo.conf"
-#define SOUNDSINFO_FILENAME    "soundsinfo.conf"
-#define MUSICINFO_FILENAME     "musicinfo.conf"
-#define ARTWORKINFO_CACHE_FILE "artworkinfo.cache"
-#define LEVELTEMPLATE_FILENAME "template.level"
-#define LEVELFILE_EXTENSION    "level"
-#define TAPEFILE_EXTENSION     "tape"
-#define SCOREFILE_EXTENSION    "score"
-
-#define GAMECONTROLLER_BASENAME        "gamecontrollerdb.txt"
-
-#define LOG_OUT_BASENAME       "stdout.txt"
-#define LOG_ERR_BASENAME       "stderr.txt"
-
-#define LOG_OUT_ID             0
-#define LOG_ERR_ID             1
-#define NUM_LOGS               2
+#define LEVELSETUP_DIRECTORY           "levelsetup"
+#define SETUP_FILENAME                 "setup.conf"
+#define USERSETUP_FILENAME             "usersetup.conf"
+#define AUTOSETUP_FILENAME             "autosetup.conf"
+#define LEVELSETUP_FILENAME            "levelsetup.conf"
+#define SERVERSETUP_FILENAME           "serversetup.conf"
+#define EDITORSETUP_FILENAME           "editorsetup.conf"
+#define EDITORCASCADE_FILENAME         "editorcascade.conf"
+#define HELPANIM_FILENAME              "helpanim.conf"
+#define HELPTEXT_FILENAME              "helptext.conf"
+#define LEVELINFO_FILENAME             "levelinfo.conf"
+#define GRAPHICSINFO_FILENAME          "graphicsinfo.conf"
+#define SOUNDSINFO_FILENAME            "soundsinfo.conf"
+#define MUSICINFO_FILENAME             "musicinfo.conf"
+#define ARTWORKINFO_CACHE_FILE         "artworkinfo.cache"
+#define LEVELTEMPLATE_FILENAME         "template.level"
+#define UPLOADED_FILENAME              ".uploaded"
+#define LEVELFILE_EXTENSION            "level"
+#define TAPEFILE_EXTENSION             "tape"
+#define SCOREFILE_EXTENSION            "score"
+
+#define GAMECONTROLLER_BASENAME                "gamecontrollerdb.txt"
+
+#define FALLBACK_TEXT_FILENAME         "fallback.txt"
 
 #define STRING_PARENT_DIRECTORY                ".."
 #define STRING_TOP_DIRECTORY           "/"
 #define STRING_NEWLINE_UNIX            "\n"
 #define STRING_NEWLINE_DOS             "\r\n"
 
-#if defined(PLATFORM_WIN32)
-#define CHAR_PATH_SEPARATOR    CHAR_PATH_SEPARATOR_DOS
-#define STRING_PATH_SEPARATOR  STRING_PATH_SEPARATOR_DOS
-#define STRING_NEWLINE         STRING_NEWLINE_DOS
+#if defined(PLATFORM_WINDOWS)
+#define CHAR_PATH_SEPARATOR            CHAR_PATH_SEPARATOR_DOS
+#define STRING_PATH_SEPARATOR          STRING_PATH_SEPARATOR_DOS
+#define STRING_NEWLINE                 STRING_NEWLINE_DOS
 #else
-#define CHAR_PATH_SEPARATOR    CHAR_PATH_SEPARATOR_UNIX
-#define STRING_PATH_SEPARATOR  STRING_PATH_SEPARATOR_UNIX
-#define STRING_NEWLINE         STRING_NEWLINE_UNIX
+#define CHAR_PATH_SEPARATOR            CHAR_PATH_SEPARATOR_UNIX
+#define STRING_PATH_SEPARATOR          STRING_PATH_SEPARATOR_UNIX
+#define STRING_NEWLINE                 STRING_NEWLINE_UNIX
 #endif
 
 
 // PAGEX3: buffer for animations
 
 // these values are hard-coded to be able to use them in initialization
-#define DOOR_GFX_PAGE_WIDTH    100     // should be set to "gfx.dxsize"
-#define DOOR_GFX_PAGE_HEIGHT   280     // should be set to "gfx.dysize"
-
-#define DOOR_GFX_PAGESIZE      (DOOR_GFX_PAGE_WIDTH)
-#define DOOR_GFX_PAGEX1                (0 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX2                (1 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX3                (2 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX4                (3 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX5                (4 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX6                (5 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX7                (6 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEX8                (7 * DOOR_GFX_PAGESIZE)
-#define DOOR_GFX_PAGEY1                (0)
-#define DOOR_GFX_PAGEY2                (DOOR_GFX_PAGE_HEIGHT)
+#define DOOR_GFX_PAGE_WIDTH            100     // should be set to "gfx.dxsize"
+#define DOOR_GFX_PAGE_HEIGHT           280     // should be set to "gfx.dysize"
+
+#define DOOR_GFX_PAGESIZE              (DOOR_GFX_PAGE_WIDTH)
+#define DOOR_GFX_PAGEX1                        (0 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX2                        (1 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX3                        (2 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX4                        (3 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX5                        (4 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX6                        (5 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX7                        (6 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX8                        (7 * DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEY1                        (0)
+#define DOOR_GFX_PAGEY2                        (DOOR_GFX_PAGE_HEIGHT)
 
 
 // macros for version handling
-#define VERSION_PART_1(x)      ((x) / 1000000)
-#define VERSION_PART_2(x)      (((x) % 1000000) / 10000)
-#define VERSION_PART_3(x)      (((x) % 10000) / 100)
-#define VERSION_PART_4(x)      ((x) % 100)
+#define VERSION_PART_1(x)              ((x) / 1000000)
+#define VERSION_PART_2(x)              (((x) % 1000000) / 10000)
+#define VERSION_PART_3(x)              (((x) % 10000) / 100)
+#define VERSION_PART_4(x)              ((x) % 100)
 
-#define VERSION_SUPER(x)       VERSION_PART_1(x)
-#define VERSION_MAJOR(x)       VERSION_PART_2(x)
-#define VERSION_MINOR(x)       VERSION_PART_3(x)
-#define VERSION_PATCH(x)       VERSION_PART_4(x)
-#define VERSION_IDENT(a,b,c,d) ((a) * 1000000 + (b) * 10000 + (c) * 100 + (d))
+#define VERSION_SUPER(x)               VERSION_PART_1(x)
+#define VERSION_MAJOR(x)               VERSION_PART_2(x)
+#define VERSION_MINOR(x)               VERSION_PART_3(x)
+#define VERSION_PATCH(x)               VERSION_PART_4(x)
+#define VERSION_IDENT(a,b,c,d)         ((a) * 1000000 + (b) * 10000 + (c) * 100 + (d))
 
 
 // macros for parent/child process identification
 #if defined(PLATFORM_UNIX)
-#define IS_PARENT_PROCESS()    (audio.mixer_pid != getpid())
-#define IS_CHILD_PROCESS()     (audio.mixer_pid == getpid())
-#define HAS_CHILD_PROCESS()    (audio.mixer_pid > 0)
+#define IS_PARENT_PROCESS()            (audio.mixer_pid != getpid())
+#define IS_CHILD_PROCESS()             (audio.mixer_pid == getpid())
+#define HAS_CHILD_PROCESS()            (audio.mixer_pid > 0)
 #else
-#define IS_PARENT_PROCESS()    TRUE
-#define IS_CHILD_PROCESS()     FALSE
-#define HAS_CHILD_PROCESS()    FALSE
+#define IS_PARENT_PROCESS()            TRUE
+#define IS_CHILD_PROCESS()             FALSE
+#define HAS_CHILD_PROCESS()            FALSE
 #endif
 
 
 // values for artwork type
-#define ARTWORK_TYPE_GRAPHICS  0
-#define ARTWORK_TYPE_SOUNDS    1
-#define ARTWORK_TYPE_MUSIC     2
+#define ARTWORK_TYPE_GRAPHICS          0
+#define ARTWORK_TYPE_SOUNDS            1
+#define ARTWORK_TYPE_MUSIC             2
 
-#define NUM_ARTWORK_TYPES      3
+#define NUM_ARTWORK_TYPES              3
 
 
 // values for tree type (chosen to match artwork type)
-#define TREE_TYPE_UNDEFINED    -1
-#define TREE_TYPE_GRAPHICS_DIR ARTWORK_TYPE_GRAPHICS
-#define TREE_TYPE_SOUNDS_DIR   ARTWORK_TYPE_SOUNDS
-#define TREE_TYPE_MUSIC_DIR    ARTWORK_TYPE_MUSIC
-#define TREE_TYPE_LEVEL_DIR    3
-#define TREE_TYPE_LEVEL_NR     4
-#define TREE_TYPE_PLAYER_NAME  5
-
-#define NUM_BASE_TREE_TYPES    4
-#define NUM_TREE_TYPES         6
-
-#define TREE_TYPE_IS_DIR(type) ((type) == TREE_TYPE_GRAPHICS_DIR ||    \
-                                (type) == TREE_TYPE_SOUNDS_DIR ||      \
-                                (type) == TREE_TYPE_MUSIC_DIR ||       \
-                                (type) == TREE_TYPE_LEVEL_DIR)
-
-#define INFOTEXT_UNDEFINED     ""
-#define INFOTEXT_GRAPHICS_DIR  "Custom Graphics"
-#define INFOTEXT_SOUNDS_DIR    "Custom Sounds"
-#define INFOTEXT_MUSIC_DIR     "Custom Music"
-#define INFOTEXT_LEVEL_DIR     "Level Sets"
-#define INFOTEXT_LEVEL_NR      "Levels"
-#define INFOTEXT_PLAYER_NAME   "Players & Teams"
-
-#define BACKLINK_TEXT_MAIN     ".. (main menu)"
-#define BACKLINK_TEXT_SETUP    ".. (setup menu)"
-#define BACKLINK_TEXT_PARENT   ".. (parent directory)"
-
-#define TREE_INFOTEXT(t)       ((t) == TREE_TYPE_PLAYER_NAME ?         \
-                                INFOTEXT_PLAYER_NAME :                 \
-                                (t) == TREE_TYPE_LEVEL_NR ?            \
-                                INFOTEXT_LEVEL_NR :                    \
-                                (t) == TREE_TYPE_LEVEL_DIR ?           \
-                                INFOTEXT_LEVEL_DIR :                   \
-                                (t) == TREE_TYPE_GRAPHICS_DIR ?        \
-                                INFOTEXT_GRAPHICS_DIR :                \
-                                (t) == TREE_TYPE_SOUNDS_DIR ?          \
-                                INFOTEXT_SOUNDS_DIR :                  \
-                                (t) == TREE_TYPE_MUSIC_DIR ?           \
-                                INFOTEXT_MUSIC_DIR :                   \
-                                INFOTEXT_UNDEFINED)
-
-#define TREE_BACKLINK_TEXT(t)  ((t) == TREE_TYPE_LEVEL_DIR ?           \
-                                BACKLINK_TEXT_MAIN :                   \
-                                BACKLINK_TEXT_SETUP)
-
-#define TREE_USERDIR(t)                ((t) == TREE_TYPE_LEVEL_DIR ?           \
-                                getUserLevelDir(NULL) :                \
-                                (t) == TREE_TYPE_GRAPHICS_DIR ?        \
-                                getUserGraphicsDir() :                 \
-                                (t) == TREE_TYPE_SOUNDS_DIR ?          \
-                                getUserSoundsDir() :                   \
-                                (t) == TREE_TYPE_MUSIC_DIR ?           \
-                                getUserMusicDir() :                    \
-                                NULL)
-
-#define TREE_FIRST_NODE_PTR(t) ((t) == TREE_TYPE_LEVEL_DIR ?           \
-                                &leveldir_first :                      \
-                                (t) == TREE_TYPE_GRAPHICS_DIR ?        \
-                                &artwork.gfx_first :                   \
-                                (t) == TREE_TYPE_SOUNDS_DIR ?          \
-                                &artwork.snd_first :                   \
-                                (t) == TREE_TYPE_MUSIC_DIR ?           \
-                                &artwork.mus_first :                   \
-                                NULL)
-
-#define TREE_FIRST_NODE(t)     ((t) == TREE_TYPE_LEVEL_DIR ?           \
-                                leveldir_first :                       \
-                                (t) == TREE_TYPE_GRAPHICS_DIR ?        \
-                                artwork.gfx_first :                    \
-                                (t) == TREE_TYPE_SOUNDS_DIR ?          \
-                                artwork.snd_first :                    \
-                                (t) == TREE_TYPE_MUSIC_DIR ?           \
-                                artwork.mus_first :                    \
-                                NULL)
+#define TREE_TYPE_UNDEFINED            -1
+#define TREE_TYPE_GRAPHICS_DIR         ARTWORK_TYPE_GRAPHICS
+#define TREE_TYPE_SOUNDS_DIR           ARTWORK_TYPE_SOUNDS
+#define TREE_TYPE_MUSIC_DIR            ARTWORK_TYPE_MUSIC
+#define TREE_TYPE_LEVEL_DIR            3
+#define TREE_TYPE_LEVEL_NR             4
+#define TREE_TYPE_PLAYER_NAME          5
+#define TREE_TYPE_SCORE_ENTRY          6
+
+#define NUM_BASE_TREE_TYPES            4
+#define NUM_TREE_TYPES                 7
+
+#define TREE_TYPE_IS_DIR(type)         ((type) == TREE_TYPE_GRAPHICS_DIR ||    \
+                                        (type) == TREE_TYPE_SOUNDS_DIR ||      \
+                                        (type) == TREE_TYPE_MUSIC_DIR ||       \
+                                        (type) == TREE_TYPE_LEVEL_DIR)
+
+#define INFOTEXT_UNDEFINED             ""
+#define INFOTEXT_GRAPHICS_DIR          "Custom Graphics"
+#define INFOTEXT_SOUNDS_DIR            "Custom Sounds"
+#define INFOTEXT_MUSIC_DIR             "Custom Music"
+#define INFOTEXT_LEVEL_DIR             "Level Sets"
+#define INFOTEXT_LEVEL_NR              "Levels"
+#define INFOTEXT_PLAYER_NAME           "Players & Teams"
+#define INFOTEXT_SCORE_ENTRY           "Hall of Fame"
+
+#define BACKLINK_TEXT_MAIN             ".. (main menu)"
+#define BACKLINK_TEXT_SETUP            ".. (setup menu)"
+#define BACKLINK_TEXT_PARENT           ".. (parent directory)"
+#define BACKLINK_TEXT_BACK             "back"
+#define BACKLINK_TEXT_NEXT             "next"
+
+#define TREE_INFOTEXT(t)                                                                       \
+                       ((t) == TREE_TYPE_SCORE_ENTRY  ? INFOTEXT_SCORE_ENTRY :                 \
+                        (t) == TREE_TYPE_PLAYER_NAME  ? INFOTEXT_PLAYER_NAME :                 \
+                        (t) == TREE_TYPE_LEVEL_NR     ? INFOTEXT_LEVEL_NR :                    \
+                        (t) == TREE_TYPE_LEVEL_DIR    ? INFOTEXT_LEVEL_DIR :                   \
+                        (t) == TREE_TYPE_GRAPHICS_DIR ? INFOTEXT_GRAPHICS_DIR :                \
+                        (t) == TREE_TYPE_SOUNDS_DIR   ? INFOTEXT_SOUNDS_DIR :                  \
+                        (t) == TREE_TYPE_MUSIC_DIR    ? INFOTEXT_MUSIC_DIR :                   \
+                        INFOTEXT_UNDEFINED)
+
+#define TREE_BACKLINK_TEXT(t)                                                                  \
+                       ((t) == TREE_TYPE_SCORE_ENTRY  ? BACKLINK_TEXT_BACK :                   \
+                        (t) == TREE_TYPE_LEVEL_DIR    ? BACKLINK_TEXT_MAIN :                   \
+                        BACKLINK_TEXT_SETUP)
+
+#define TREE_USERDIR(t)                                                                                \
+                       ((t) == TREE_TYPE_LEVEL_DIR    ? getUserLevelDir(NULL) :                \
+                        (t) == TREE_TYPE_GRAPHICS_DIR ? getUserGraphicsDir() :                 \
+                        (t) == TREE_TYPE_SOUNDS_DIR   ? getUserSoundsDir() :                   \
+                        (t) == TREE_TYPE_MUSIC_DIR    ? getUserMusicDir() :                    \
+                        NULL)
+
+#define TREE_FIRST_NODE_PTR(t)                                                                 \
+                       ((t) == TREE_TYPE_LEVEL_DIR    ? &leveldir_first :                      \
+                        (t) == TREE_TYPE_GRAPHICS_DIR ? &artwork.gfx_first :                   \
+                        (t) == TREE_TYPE_SOUNDS_DIR   ? &artwork.snd_first :                   \
+                        (t) == TREE_TYPE_MUSIC_DIR    ? &artwork.mus_first :                   \
+                        NULL)
+
+#define TREE_FIRST_NODE(t)                                                                     \
+                       ((t) == TREE_TYPE_LEVEL_DIR    ? leveldir_first :                       \
+                        (t) == TREE_TYPE_GRAPHICS_DIR ? artwork.gfx_first :                    \
+                        (t) == TREE_TYPE_SOUNDS_DIR   ? artwork.snd_first :                    \
+                        (t) == TREE_TYPE_MUSIC_DIR    ? artwork.mus_first :                    \
+                        NULL)
 
 // values for artwork handling
-#define LEVELDIR_ARTWORK_SET_PTR(leveldir, type)                       \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                &(leveldir)->graphics_set :            \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                &(leveldir)->sounds_set :              \
-                                &(leveldir)->music_set)
-
-#define LEVELDIR_ARTWORK_SET(leveldir, type)                           \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (leveldir)->graphics_set :             \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (leveldir)->sounds_set :               \
-                                (leveldir)->music_set)
-
-#define LEVELDIR_ARTWORK_PATH_PTR(leveldir, type)                      \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                &(leveldir)->graphics_path :           \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                &(leveldir)->sounds_path :             \
-                                &(leveldir)->music_path)
-
-#define LEVELDIR_ARTWORK_PATH(leveldir, type)                          \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (leveldir)->graphics_path :            \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (leveldir)->sounds_path :              \
-                                (leveldir)->music_path)
-
-#define SETUP_ARTWORK_SET(setup, type)                                 \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (setup).graphics_set :                 \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (setup).sounds_set :                   \
-                                (setup).music_set)
-
-#define SETUP_OVERRIDE_ARTWORK(setup, type)                            \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (setup).override_level_graphics :      \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (setup).override_level_sounds :        \
-                                (setup).override_level_music)
-
-#define GFX_OVERRIDE_ARTWORK(type)                                     \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                gfx.override_level_graphics :          \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                gfx.override_level_sounds :            \
-                                gfx.override_level_music)
-
-#define ARTWORK_FIRST_NODE(artwork, type)                              \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (artwork).gfx_first :                  \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (artwork).snd_first :                  \
-                                (artwork).mus_first)
-
-#define ARTWORK_CURRENT_PTR(artwork, type)                             \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                &(artwork).gfx_current :               \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                &(artwork).snd_current :               \
-                                &(artwork).mus_current)
-
-#define ARTWORK_CURRENT(artwork, type)                                 \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (artwork).gfx_current :                \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (artwork).snd_current :                \
-                                (artwork).mus_current)
-
-#define ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)                  \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                &(artwork).gfx_current_identifier :    \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                &(artwork).snd_current_identifier :    \
-                                &(artwork).mus_current_identifier)
-
-#define ARTWORK_CURRENT_IDENTIFIER(artwork, type)                      \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (artwork).gfx_current_identifier :     \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (artwork).snd_current_identifier :     \
-                                (artwork).mus_current_identifier)
-
-#define ARTWORKINFO_FILENAME(type)                                     \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                GRAPHICSINFO_FILENAME :                \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                SOUNDSINFO_FILENAME :                  \
-                                (type) == ARTWORK_TYPE_MUSIC ?         \
-                                MUSICINFO_FILENAME : "")
-
-#define ARTWORK_DIRECTORY(type)                                                \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                GRAPHICS_DIRECTORY :                   \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                SOUNDS_DIRECTORY :                     \
-                                (type) == ARTWORK_TYPE_MUSIC ?         \
-                                MUSIC_DIRECTORY : "")
-
-#define OPTIONS_ARTWORK_DIRECTORY(type)                                        \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                options.graphics_directory :           \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                options.sounds_directory :             \
-                                (type) == ARTWORK_TYPE_MUSIC ?         \
-                                options.music_directory : "")
-
-#define USER_ARTWORK_DIRECTORY(type)                                   \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                getUserGraphicsDir() :                 \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                getUserSoundsDir() :                   \
-                                (type) == ARTWORK_TYPE_MUSIC ?         \
-                                getUserMusicDir() : "")
-
-#define ARTWORK_DEFAULT_SUBDIR(type)                                   \
-                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                GFX_DEFAULT_SUBDIR :                   \
-                                (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                SND_DEFAULT_SUBDIR :                   \
-                                MUS_DEFAULT_SUBDIR)
+#define LEVELDIR_ARTWORK_SET_PTR(leveldir, type)                                               \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? &leveldir->graphics_set :            \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? &leveldir->sounds_set :              \
+                        &leveldir->music_set)
+
+#define LEVELDIR_ARTWORK_SET(leveldir, type)                                                   \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? leveldir->graphics_set :             \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? leveldir->sounds_set :               \
+                        leveldir->music_set)
+
+#define LEVELDIR_ARTWORK_PATH_PTR(leveldir, type)                                              \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? &leveldir->graphics_path :           \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? &leveldir->sounds_path :             \
+                        &leveldir->music_path)
+
+#define LEVELDIR_ARTWORK_PATH(leveldir, type)                                                  \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? leveldir->graphics_path :            \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? leveldir->sounds_path :              \
+                        leveldir->music_path)
+
+#define SETUP_ARTWORK_SET(setup, type)                                                         \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? setup.graphics_set :                 \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? setup.sounds_set :                   \
+                        setup.music_set)
+
+#define SETUP_OVERRIDE_ARTWORK(setup, type)                                                    \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? setup.override_level_graphics :      \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? setup.override_level_sounds :        \
+                        setup.override_level_music)
+
+#define GFX_OVERRIDE_ARTWORK(type)                                                             \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? gfx.override_level_graphics :        \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? gfx.override_level_sounds :          \
+                        gfx.override_level_music)
+
+#define ARTWORK_FIRST_NODE(artwork, type)                                                      \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? artwork.gfx_first :                  \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? artwork.snd_first :                  \
+                        artwork.mus_first)
+
+#define ARTWORK_CURRENT_PTR(artwork, type)                                                     \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? &artwork.gfx_current :               \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? &artwork.snd_current :               \
+                        &artwork.mus_current)
+
+#define ARTWORK_CURRENT(artwork, type)                                                         \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? artwork.gfx_current :                \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? artwork.snd_current :                \
+                        artwork.mus_current)
+
+#define ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)                                          \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? &artwork.gfx_current_identifier :    \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? &artwork.snd_current_identifier :    \
+                        &artwork.mus_current_identifier)
+
+#define ARTWORK_CURRENT_IDENTIFIER(artwork, type)                                              \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? artwork.gfx_current_identifier :     \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? artwork.snd_current_identifier :     \
+                        artwork.mus_current_identifier)
+
+#define ARTWORKINFO_FILENAME(type)                                                             \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? GRAPHICSINFO_FILENAME :              \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? SOUNDSINFO_FILENAME :                \
+                        (type) == ARTWORK_TYPE_MUSIC    ? MUSICINFO_FILENAME :                 \
+                        "")
+
+#define ARTWORK_DIRECTORY(type)                                                                        \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? GRAPHICS_DIRECTORY :                 \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? SOUNDS_DIRECTORY :                   \
+                        (type) == ARTWORK_TYPE_MUSIC    ? MUSIC_DIRECTORY :                    \
+                        "")
+
+#define OPTIONS_ARTWORK_DIRECTORY(type)                                                                \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? options.graphics_directory :         \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? options.sounds_directory :           \
+                        (type) == ARTWORK_TYPE_MUSIC    ? options.music_directory :            \
+                        "")
+
+#define USER_ARTWORK_DIRECTORY(type)                                                           \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? getUserGraphicsDir() :               \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? getUserSoundsDir() :                 \
+                        (type) == ARTWORK_TYPE_MUSIC    ? getUserMusicDir() :                  \
+                        "")
+
+#define ARTWORK_DEFAULT_SUBDIR(type)                                                           \
+                       ((type) == ARTWORK_TYPE_GRAPHICS ? GFX_DEFAULT_SUBDIR :                 \
+                        (type) == ARTWORK_TYPE_SOUNDS   ? SND_DEFAULT_SUBDIR :                 \
+                        MUS_DEFAULT_SUBDIR)
 
 #define UPDATE_BUSY_STATE()                    \
 {                                              \
   if (gfx.draw_busy_anim_function != NULL)     \
-    gfx.draw_busy_anim_function();             \
+    gfx.draw_busy_anim_function(TRUE);         \
+}
+#define UPDATE_BUSY_STATE_NOT_LOADING()                \
+{                                              \
+  if (gfx.draw_busy_anim_function != NULL)     \
+    gfx.draw_busy_anim_function(FALSE);                \
 }
 
 
@@ -999,17 +991,17 @@ struct ProgramInfo
   char *userdata_subdir;       // personal user game data directory
   char *userdata_path;         // resulting full path to game data directory
 
+  char *program_basename;
   char *program_title;
   char *window_title;
-  char *icon_title;
 
   char *icon_filename;
 
   char *cookie_prefix;
 
-  char *log_filename[NUM_LOGS];                // log filenames for out/err messages
-  FILE *log_file[NUM_LOGS];            // log file handles for out/err files
-  FILE *log_file_default[NUM_LOGS];    // default log file handles (out/err)
+  char *log_filename;          // filename for log messages
+  FILE *log_file;              // file handle for log files
+  FILE *log_file_default;      // default log file handle
 
   int version_super;
   int version_major;
@@ -1023,6 +1015,8 @@ struct ProgramInfo
   void (*exit_message_function)(char *, va_list);
   void (*exit_function)(int);
 
+  int api_thread_count;
+
   boolean headless;
 };
 
@@ -1069,6 +1063,8 @@ struct OptionInfo
   char *identifier;
   char *level_nr;
 
+  int display_nr;
+
   boolean mytapes;
   boolean serveronly;
   boolean network;
@@ -1096,14 +1092,12 @@ struct VideoSystemInfo
   int vsync_mode;
 
   unsigned int frame_counter;
-  unsigned int frame_delay;
-  unsigned int frame_delay_value;
+  DelayCounter frame_delay;
 
   boolean shifted_up;
   int shifted_up_pos;
   int shifted_up_pos_last;
-  unsigned int shifted_up_delay;
-  unsigned int shifted_up_delay_value;
+  DelayCounter shifted_up_delay;
 
   boolean initialized;
 };
@@ -1122,6 +1116,8 @@ struct AudioSystemInfo
   char *device_name;
   int device_fd;
 
+  int sample_rate;
+
   int num_channels;
   int music_channel;
   int first_sound_channel;
@@ -1198,13 +1194,16 @@ struct GfxInfo
   struct FontBitmapInfo *font_bitmap_info;
   int (*select_font_function)(int);
   int (*get_font_from_token_function)(char *);
+  char * (*get_token_from_font_function)(int);
 
   int anim_random_frame;
+  int anim_first_level;
 
-  void (*draw_busy_anim_function)(void);
+  void (*draw_busy_anim_function)(boolean);
   void (*draw_global_anim_function)(int, int);
   void (*draw_global_border_function)(int);
-  void (*draw_tile_cursor_function)(int);
+  void (*draw_tile_cursor_function)(int, int);
+  void (*draw_envelope_request_function)(int);
 
   int cursor_mode;
   int cursor_mode_override;
@@ -1280,6 +1279,8 @@ struct SetupTouchInfo
   boolean draw_pressed;
 
   boolean grid_initialized;
+
+  boolean overlay_buttons;
 };
 
 struct SetupInputInfo
@@ -1292,6 +1293,8 @@ struct SetupInputInfo
 struct SetupEditorInfo
 {
   boolean el_boulderdash;
+  boolean el_boulderdash_native;
+  boolean el_boulderdash_effects;
   boolean el_emerald_mine;
   boolean el_emerald_mine_club;
   boolean el_more;
@@ -1336,6 +1339,8 @@ struct SetupLevelSetupInfo
 struct SetupEditorCascadeInfo
 {
   boolean el_bd;
+  boolean el_bdx;
+  boolean el_bdx_effects;
   boolean el_em;
   boolean el_emc;
   boolean el_rnd;
@@ -1349,6 +1354,7 @@ struct SetupEditorCascadeInfo
   boolean el_steel_chars;
   boolean el_ce;
   boolean el_ge;
+  boolean el_es;
   boolean el_ref;
   boolean el_user;
   boolean el_dynamic;
@@ -1358,6 +1364,8 @@ struct SetupShortcutInfo
 {
   Key save_game;
   Key load_game;
+  Key restart_game;
+  Key pause_before_end;
   Key toggle_pause;
 
   Key focus_player[MAX_PLAYERS];
@@ -1378,6 +1386,9 @@ struct SetupShortcutInfo
   Key snap_right;
   Key snap_up;
   Key snap_down;
+
+  Key speed_fast;
+  Key speed_slow;
 };
 
 struct SetupSystemInfo
@@ -1416,6 +1427,7 @@ struct SetupInternalInfo
   boolean choose_from_top_leveldir;
   boolean show_scaling_in_title;
   boolean create_user_levelset;
+  boolean info_screens_from_main;
 
   boolean menu_game;
   boolean menu_engines;
@@ -1428,6 +1440,22 @@ struct SetupInternalInfo
   boolean menu_shortcuts;
   boolean menu_exit;
   boolean menu_save_and_exit;
+
+  boolean menu_shortcuts_various;
+  boolean menu_shortcuts_focus;
+  boolean menu_shortcuts_tape;
+  boolean menu_shortcuts_sound;
+  boolean menu_shortcuts_snap;
+  boolean menu_shortcuts_speed;
+
+  boolean info_title;
+  boolean info_elements;
+  boolean info_music;
+  boolean info_credits;
+  boolean info_program;
+  boolean info_version;
+  boolean info_levelset;
+  boolean info_exit;
 };
 
 struct SetupDebugInfo
@@ -1445,6 +1473,7 @@ struct SetupInfo
 {
   char *player_name;
   char *player_uuid;
+  int player_version;
 
   boolean multiple_users;
 
@@ -1453,6 +1482,7 @@ struct SetupInfo
   boolean sound_music;
   boolean sound_simple;
   boolean toons;
+  boolean global_animations;
   boolean scroll_delay;
   boolean forced_scroll_delay;
   int scroll_delay_value;
@@ -1460,11 +1490,14 @@ struct SetupInfo
   int engine_snapshot_memory;
   boolean fade_screens;
   boolean autorecord;
+  boolean autorecord_after_replay;
+  boolean auto_pause_on_start;
   boolean show_titlescreen;
   boolean quick_doors;
   boolean team_mode;
   boolean handicap;
   boolean skip_levels;
+  boolean allow_skipping_levels;
   boolean increment_levels;
   boolean auto_play_next_level;
   boolean count_score_after_game;
@@ -1487,6 +1520,20 @@ struct SetupInfo
   boolean prefer_extra_panel_items;
   boolean game_speed_extended;
   int game_frame_delay;
+  int default_game_engine_type;
+  boolean bd_skip_uncovering;
+  boolean bd_skip_hatching;
+  boolean bd_scroll_delay;
+  boolean bd_show_invisible_outbox;
+  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_palette_c64;
+  int bd_palette_c64dtv;
+  int bd_palette_atari;
+  int bd_default_color_type;
+  int bd_random_colors;
   boolean sp_show_border_elements;
   boolean small_game_graphics;
   boolean show_load_save_buttons;
@@ -1496,13 +1543,14 @@ struct SetupInfo
   char *graphics_set;
   char *sounds_set;
   char *music_set;
-  int override_level_graphics;         // not boolean -- can also be "AUTO"
-  int override_level_sounds;           // not boolean -- can also be "AUTO"
-  int override_level_music;            // not boolean -- can also be "AUTO"
+  int override_level_graphics;         // not boolean -- can also be "MODE_AUTO"
+  int override_level_sounds;           // not boolean -- can also be "MODE_AUTO"
+  int override_level_music;            // not boolean -- can also be "MODE_AUTO"
 
   int volume_simple;
   int volume_loops;
   int volume_music;
+  boolean audio_sample_rate_44100;
 
   boolean network_mode;
   int network_player_nr;
@@ -1512,7 +1560,10 @@ struct SetupInfo
   char *api_server_hostname;
   char *api_server_password;
   boolean ask_for_uploading_tapes;
+  boolean ask_for_remaining_tapes;
   boolean provide_uploading_tapes;
+  boolean ask_for_using_api_server;
+  boolean has_remaining_tapes;
 
   struct SetupAutoSetupInfo auto_setup;
   struct SetupLevelSetupInfo level_setup;
@@ -1536,74 +1587,80 @@ struct UserInfo
 
 struct TreeInfo
 {
-  struct TreeInfo **node_top;          // topmost node in tree
-  struct TreeInfo *node_parent;                // parent level directory info
-  struct TreeInfo *node_group;         // level group sub-directory info
-  struct TreeInfo *next;               // next level series structure node
+  struct TreeInfo **node_top;  // topmost node in tree
+  struct TreeInfo *node_parent;        // parent level directory info
+  struct TreeInfo *node_group; // level group sub-directory info
+  struct TreeInfo *next;       // next level series structure node
 
-  int cl_first;                // internal control field for setup screen
-  int cl_cursor;       // internal control field for setup screen
+  int cl_first;                        // internal control field for setup screen
+  int cl_cursor;               // internal control field for setup screen
 
-  int type;            // type of tree content
+  int type;                    // type of tree content
 
   // fields for "type == TREE_TYPE_LEVEL_DIR"
 
-  char *subdir;                // tree info sub-directory basename (may be ".")
-  char *fullpath;      // complete path relative to tree base directory
-  char *basepath;      // absolute base path of tree base directory
-  char *identifier;    // identifier string for configuration files
-  char *name;          // tree info name, as displayed in selection menues
-  char *name_sorting;  // optional sorting name for correct name sorting
-  char *author;                // level or artwork author name
-  char *year;          // optional year of creation for levels or artwork
-
-  char *program_title;    // optional alternative text for program title
-  char *program_copyright; // optional alternative text for program copyright
-  char *program_company;   // optional alternative text for program company
-
-  char *imported_from; // optional comment for imported levels or artwork
-  char *imported_by;   // optional comment for imported levels or artwork
-  char *tested_by;     // optional comment to name people who tested a set
-
-  char *graphics_set_ecs; // special EMC custom graphics set (ECS graphics)
-  char *graphics_set_aga; // special EMC custom graphics set (AGA graphics)
-  char *graphics_set;  // optional custom graphics set (level tree only)
-  char *sounds_set_default; // default EMC custom sounds set
-  char *sounds_set_lowpass; // special EMC custom sounds set (lowpass filter)
-  char *sounds_set;    // optional custom sounds set (level tree only)
-  char *music_set;     // optional custom music set (level tree only)
-  char *graphics_path; // path to optional custom graphics set (level only)
-  char *sounds_path;   // path to optional custom sounds set (level only)
-  char *music_path;    // path to optional custom music set (level only)
-
-  char *level_filename;        // filename of level file (for packed level file)
-  char *level_filetype;        // type of levels in level directory or level file
-
-  char *special_flags; // flags for special actions performed on level file
-
-  int levels;          // number of levels in level series
-  int first_level;     // first level number (to allow start with 0 or 1)
-  int last_level;      // last level number (automatically calculated)
-  int sort_priority;   // sort levels by 'sort_priority' and then by name
-
-  boolean latest_engine;// force level set to use the latest game engine
-
-  boolean level_group; // directory contains more level series directories
-  boolean parent_link; // entry links back to parent directory
-  boolean is_copy;     // this entry is a copy of another entry in the tree
-  boolean in_user_dir; // user defined levels are stored in home directory
-  boolean user_defined;        // levels in user directory and marked as "private"
-  boolean readonly;    // readonly levels can not be changed with editor
-  boolean handicap;    // level set has no handicap when set to "false"
-  boolean skip_levels; // levels can be skipped when set to "true"
-
-  boolean use_emc_tiles;// use (swapped) V5/V6 EMC tiles when set to "true"
-
-  int color;           // color to use on selection screen for this level
-  char *class_desc;    // description of level series class
-  int handicap_level;  // number of the lowest unsolved level
-
-  char *infotext;      // optional text to describe the tree type (headline)
+  char *subdir;                        // tree info sub-directory basename (may be ".")
+  char *fullpath;              // complete path relative to tree base directory
+  char *basepath;              // absolute base path of tree base directory
+  char *identifier;            // identifier string for configuration files
+  char *name;                  // tree info name, as displayed in selection menues
+  char *name_sorting;          // optional sorting name for correct name sorting
+  char *author;                        // level or artwork author name
+  char *year;                  // optional year of creation for levels or artwork
+
+  char *program_title;         // optional alternative text for program title
+  char *program_copyright;     // optional alternative text for program copyright
+  char *program_company;       // optional alternative text for program company
+
+  char *imported_from;         // optional comment for imported levels or artwork
+  char *imported_by;           // optional comment for imported levels or artwork
+  char *tested_by;             // optional comment to name people who tested a set
+
+  char *graphics_set_ecs;      // special EMC custom graphics set (ECS graphics)
+  char *graphics_set_aga;      // special EMC custom graphics set (AGA graphics)
+  char *graphics_set;          // optional custom graphics set (level tree only)
+  char *sounds_set_default;    // default EMC custom sounds set
+  char *sounds_set_lowpass;    // special EMC custom sounds set (lowpass filter)
+  char *sounds_set;            // optional custom sounds set (level tree only)
+  char *music_set;             // optional custom music set (level tree only)
+  char *graphics_path;         // path to optional custom graphics set (level only)
+  char *sounds_path;           // path to optional custom sounds set (level only)
+  char *music_path;            // path to optional custom music set (level only)
+
+  char *level_filename;                // filename of level file (for packed level file)
+  char *level_filetype;                // type of levels in level directory or level file
+
+  char *special_flags;         // flags for special actions performed on level file
+
+  char *empty_level_name;      // name pattern if level title is "nameless level"
+  boolean force_level_name;    // force also renaming non-nameless level titles
+
+  int levels;                  // number of levels in level series
+  int first_level;             // first level number (to allow start with 0 or 1)
+  int last_level;              // last level number (automatically calculated)
+  int sort_priority;           // sort levels by 'sort_priority' and then by name
+  int pos;                     // custom position information of node in tree
+
+  boolean latest_engine;       // force level set to use the latest game engine
+
+  boolean level_group;         // directory contains more level series directories
+  boolean parent_link;         // entry links back to parent directory
+  boolean is_copy;             // this entry is a copy of another entry in the tree
+  boolean in_user_dir;         // user defined levels are stored in home directory
+  boolean user_defined;                // levels in user directory and marked as "private"
+  boolean readonly;            // readonly levels can not be changed with editor
+  boolean handicap;            // level set has no handicap when set to "false"
+  boolean time_limit;          // level set has no time limit when set to "false"
+  boolean skip_levels;         // levels can be skipped when set to "true"
+
+  boolean use_emc_tiles;       // use (swapped) V5/V6 EMC tiles when set to "true"
+  boolean info_screens_from_main; // can invoke info screens from main menu
+
+  int color;                   // color to use on selection screen for this level
+  char *class_desc;            // description of level series class
+  int handicap_level;          // number of the lowest unsolved level
+
+  char *infotext;              // optional text to describe the tree type (headline)
 };
 
 typedef struct TreeInfo TreeInfo;
@@ -1851,7 +1908,6 @@ extern struct AudioSystemInfo     audio;
 extern struct GfxInfo          gfx;
 extern struct TileCursorInfo   tile_cursor;
 extern struct OverlayInfo      overlay;
-extern struct AnimInfo         anim;
 extern struct ArtworkInfo      artwork;
 extern struct JoystickInfo     joystick;
 extern struct SetupInfo                setup;
@@ -1903,10 +1959,11 @@ void InitGfxDoor3Info(int, int, int, int);
 void InitGfxWindowInfo(int, int);
 void InitGfxScrollbufferInfo(int, int);
 void InitGfxClipRegion(boolean, int, int, int, int);
-void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(void));
+void InitGfxDrawBusyAnimFunction(void (*draw_busy_anim_function)(boolean));
 void InitGfxDrawGlobalAnimFunction(void (*draw_global_anim_function)(int, int));
 void InitGfxDrawGlobalBorderFunction(void (*draw_global_border_function)(int));
-void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int));
+void InitGfxDrawTileCursorFunction(void (*draw_tile_cursor_function)(int, int));
+void InitGfxDrawEnvelopeRequestFunction(void (*draw_envelope_request_function)(int));
 void InitGfxCustomArtworkInfo(void);
 void InitGfxOtherSettings(void);
 void InitTileCursorInfo(void);
@@ -1925,9 +1982,7 @@ boolean GetOverlayActive(void);
 void SetDrawDeactivationMask(int);
 int GetDrawDeactivationMask(void);
 void SetDrawBackgroundMask(int);
-void SetWindowBackgroundBitmap(Bitmap *);
-void SetMainBackgroundBitmap(Bitmap *);
-void SetDoorBackgroundBitmap(Bitmap *);
+void SetBackgroundBitmap(Bitmap *, int, int, int, int, int);
 void SetRedrawMaskFromArea(int, int, int, int);
 
 void LimitScreenUpdates(boolean);
@@ -1936,12 +1991,14 @@ void InitVideoDefaults(void);
 void InitVideoDisplay(void);
 void CloseVideoDisplay(void);
 void InitVideoBuffer(int, int, int, boolean);
+void ResetBitmapAlpha(Bitmap *);
 Bitmap *CreateBitmapStruct(void);
 Bitmap *CreateBitmap(int, int, int);
 void ReCreateBitmap(Bitmap **, int, int);
 void FreeBitmap(Bitmap *);
+void SetBitmapAlphaNextBlit(Bitmap *, int);
 void BlitBitmap(Bitmap *, Bitmap *, int, int, int, int, int, int);
-void BlitBitmapTiled(Bitmap *, Bitmap *, int, int, int, int, int, int, int,int);
+void BlitBitmapTiled(Bitmap *, Bitmap *, int, int, int, int, int, int, int, int);
 void FadeRectangle(int, int, int, int, int, int, int,
                   void (*draw_border_function)(void));
 void FillRectangle(Bitmap *, int, int, int, int, Pixel);
@@ -1949,7 +2006,7 @@ void ClearRectangle(Bitmap *, int, int, int, int);
 void ClearRectangleOnBackground(Bitmap *, int, int, int, int);
 void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
 boolean DrawingDeactivatedField(void);
-boolean DrawingDeactivated(int, int, int, int);
+boolean DrawingDeactivated(int, int);
 boolean DrawingOnBackground(int, int);
 boolean DrawingAreaChanged(void);
 void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int, int);
@@ -1957,12 +2014,10 @@ void BlitTexture(Bitmap *, int, int, int, int, int, int);
 void BlitTextureMasked(Bitmap *, int, int, int, int, int, int);
 void BlitToScreen(Bitmap *, int, int, int, int, int, int);
 void BlitToScreenMasked(Bitmap *, int, int, int, int, int, int);
-void DrawSimpleBlackLine(Bitmap *, int, int, int, int);
 void DrawSimpleWhiteLine(Bitmap *, int, int, int, int);
 void DrawLines(Bitmap *, struct XY *, int, Pixel);
 Pixel GetPixel(Bitmap *, int, int);
-Pixel GetPixelFromRGB(Bitmap *, unsigned int,unsigned int,unsigned int);
-Pixel GetPixelFromRGBcompact(Bitmap *, unsigned int);
+Pixel GetPixelFromRGB(Bitmap *, unsigned int, unsigned int, unsigned int);
 
 void KeyboardAutoRepeatOn(void);
 void KeyboardAutoRepeatOff(void);
@@ -1996,13 +2051,14 @@ void WaitEvent(Event *event);
 void PeekEvent(Event *event);
 void PumpEvents(void);
 void CheckQuitEvent(void);
-Key GetEventKey(KeyEvent *, boolean);
+Key GetEventKey(KeyEvent *);
 KeyMod HandleKeyModState(Key, int);
 KeyMod GetKeyModState(void);
 KeyMod GetKeyModStateFromEvents(void);
 void StartTextInput(int, int, int, int);
 void StopTextInput(void);
 void PushUserEvent(int, int, int);
+boolean PendingEscapeKeyEvent(void);
 
 void InitJoysticks(void);
 boolean ReadJoystick(int, int *, int *, boolean *, boolean *);
index 17475e8c721247b0d92a51532229275e6676e78b..446a873b23dcfd9c137ed1792b1399f1525ed1d6 100644 (file)
 #include "misc.h"
 
 
+// ============================================================================
+// static font variables
+// ============================================================================
+
+boolean text_drawing_enabled = TRUE;
+
+
 // ============================================================================
 // font functions
 // ============================================================================
 
+void EnableDrawingText(void)
+{
+  text_drawing_enabled = TRUE;
+}
+
+void DisableDrawingText(void)
+{
+  text_drawing_enabled = FALSE;
+}
+
 void InitFontInfo(struct FontBitmapInfo *font_bitmap_info, int num_fonts,
                  int (*select_font_function)(int),
-                 int (*get_font_from_token_function)(char *))
+                 int (*get_font_from_token_function)(char *),
+                 char * (*get_token_from_font_function)(int))
 {
   gfx.num_fonts = num_fonts;
   gfx.font_bitmap_info = font_bitmap_info;
   gfx.select_font_function = select_font_function;
   gfx.get_font_from_token_function = get_font_from_token_function;
+  gfx.get_token_from_font_function = get_token_from_font_function;
 }
 
 void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info)
@@ -82,12 +101,13 @@ static int getFontCharPosition(int font_nr, char c)
 {
   int font_bitmap_id = gfx.select_font_function(font_nr);
   struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
-  boolean default_font = (font->num_chars == DEFAULT_NUM_CHARS_PER_FONT);
   int font_pos = (unsigned char)c - 32;
 
   // map some special characters to their ascii values in default font
-  if (default_font)
+  if (font->num_chars == DEFAULT_NUM_CHARS_PER_FONT)
     font_pos = MAP_FONT_ASCII(c) - 32;
+  else if (font->num_chars == NUM_CHARS_PER_FONT_EXT)
+    font_pos = MAP_FONT_ASCII_EXT(c) - 32;
 
   // this allows dynamic special characters together with special font
   if (font_pos < 0 || font_pos >= font->num_chars)
@@ -142,6 +162,9 @@ static void DrawInitTextExt(char *text, int ypos, int font_nr, boolean update)
 
   UPDATE_BUSY_STATE();
 
+  if (!text_drawing_enabled)
+    return;
+
   if (window != NULL &&
       gfx.draw_init_text &&
       gfx.num_fonts > 0 &&
@@ -152,8 +175,8 @@ static void DrawInitTextExt(char *text, int ypos, int font_nr, boolean update)
     int width = video.width;
     int height = getFontHeight(font_nr);
 
-    ClearRectangle(drawto, 0, y, width, height);
-    DrawTextExt(drawto, x, y, text, font_nr, BLIT_OPAQUE);
+    ClearRectangleOnBackground(drawto, 0, y, width, height);
+    DrawTextExt(drawto, x, y, text, font_nr, BLIT_MASKED);
 
     if (update)
       BlitBitmap(drawto, window, 0, 0, video.width, video.height, 0, 0);
@@ -223,12 +246,6 @@ void DrawTextSAligned(int x, int y, char *text, int font_nr, int align)
           gfx.sy + y, text, font_nr);
 }
 
-void DrawTextAligned(int x, int y, char *text, int font_nr, int align)
-{
-  DrawText(ALIGNED_XPOS(x, getTextWidth(text, font_nr), align),
-          y, text, font_nr);
-}
-
 void DrawText(int x, int y, char *text, int font_nr)
 {
   int mask_mode = BLIT_OPAQUE;
@@ -260,6 +277,14 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
   int src_x, src_y;
   char *text_ptr = text;
 
+  if (!text_drawing_enabled)
+    return;
+
+#if DEBUG
+  Debug("font:token", "'%s' / '%s'",
+        gfx.get_token_from_font_function(font_nr), text);
+#endif
+
   if (font->bitmap == NULL)
     return;
 
@@ -357,11 +382,24 @@ char *GetTextBufferFromFile(char *filename, int max_lines)
   while (!checkEndOfFile(file) && num_lines < max_lines)
   {
     char line[MAX_LINE_LEN];
+    char *line_ptr;
+    int line_len;
 
     // read next line of input file
     if (!getStringFromFile(file, line, MAX_LINE_LEN))
       break;
 
+    line_len = strlen(line);
+
+    // cut trailing line break (this can be newline and/or carriage return)
+    for (line_ptr = &line[line_len]; line_ptr >= line; line_ptr--)
+      if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
+       *line_ptr = '\0';
+
+    // re-add newline (so the result is terminated by newline, but not CR/LF)
+    if (strlen(line) != line_len)
+      strcat(line, "\n");
+
     buffer = checked_realloc(buffer, strlen(buffer) + strlen(line) + 1);
 
     strcat(buffer, line);
@@ -371,6 +409,15 @@ char *GetTextBufferFromFile(char *filename, int max_lines)
 
   closeFile(file);
 
+  if (getTextEncoding(buffer) == TEXT_ENCODING_UTF_8)
+  {
+    char *body_latin1 = getLatin1FromUTF8(buffer);
+
+    checked_free(buffer);
+
+    buffer = body_latin1;
+  }
+
   return buffer;
 }
 
@@ -388,6 +435,9 @@ static boolean RenderLineToBuffer(char **src_buffer_ptr, char *dst_buffer,
     char *word_ptr;
     int word_len;
 
+    if (strEqual(text_ptr, "  "))      // special case: force line break
+      buffer_filled = TRUE;
+
     // skip leading whitespaces
     while (*text_ptr == ' ' || *text_ptr == '\t')
       text_ptr++;
@@ -475,16 +525,18 @@ static boolean getCheckedTokenValueFromString(char *string, char **token,
   return TRUE;
 }
 
-static void DrawTextBuffer_Flush(int x, int y, char *buffer, int font_nr,
-                                int line_length, int cut_length,
+static void DrawTextBuffer_Flush(int x, int y, char *buffer, int base_font_nr,
+                                int font_nr, int line_length, int cut_length,
                                 int mask_mode, boolean centered,
                                 int current_ypos)
 {
   int buffer_len = strlen(buffer);
+  int base_font_width = getFontWidth(base_font_nr);
   int font_width = getFontWidth(font_nr);
   int offset_chars = (centered ? (line_length - buffer_len) / 2 : 0);
-  int offset_xsize =
-    (centered ? font_width * (line_length - buffer_len) / 2 : 0);
+  int line_width = base_font_width * line_length;
+  int buffer_width = font_width * buffer_len;
+  int offset_xsize = (centered ? (line_width - buffer_width) / 2 : 0);
   int final_cut_length = MAX(0, cut_length - offset_chars);
   int xx = x + offset_xsize;
   int yy = y + current_ypos;
@@ -497,13 +549,15 @@ static void DrawTextBuffer_Flush(int x, int y, char *buffer, int font_nr,
     DrawText(xx, yy, buffer, font_nr);
 }
 
-int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
-                  int line_length, int cut_length, int max_lines,
-                  int line_spacing, int mask_mode, boolean autowrap,
-                  boolean centered, boolean parse_comments)
+static int DrawTextBufferExt(int x, int y, char *text_buffer, int base_font_nr,
+                            int line_length, int cut_length, int max_lines,
+                            int line_spacing, int mask_mode, boolean autowrap,
+                            boolean centered, boolean parse_comments,
+                            boolean is_text_area)
 {
   char buffer[line_length + 1];
   int buffer_len;
+  int font_nr = base_font_nr;
   int font_height = getFontHeight(font_nr);
   int line_height = font_height + line_spacing;
   int current_line = 0;
@@ -532,8 +586,16 @@ int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
 
     // copy next line from text buffer to line buffer (nearly fgets() style)
     for (i = 0; i < num_line_chars && *text_buffer; i++)
+    {
       if ((line[i] = *text_buffer++) == '\n')
+      {
+       // in text areas, 'line_length' sized lines cause additional empty line
+       if (i == line_length && is_text_area)
+         text_buffer--;
+
        break;
+      }
+    }
     line[i] = '\0';
 
     // prevent 'num_line_chars' sized lines to cause additional empty line
@@ -551,8 +613,8 @@ int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
        // if found, flush the current buffer, if non-empty
        if (buffer_len > 0 && current_ypos < max_ysize)
        {
-         DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
-                              mask_mode, centered, current_ypos);
+         DrawTextBuffer_Flush(x, y, buffer, base_font_nr, font_nr, line_length,
+                              cut_length, mask_mode, centered, current_ypos);
          current_ypos += line_height;
          current_line++;
 
@@ -622,8 +684,8 @@ int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
 
       if (buffer_filled)
       {
-       DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
-                            mask_mode, centered, current_ypos);
+       DrawTextBuffer_Flush(x, y, buffer, base_font_nr, font_nr, line_length,
+                            cut_length, mask_mode, centered, current_ypos);
        current_ypos += line_height;
        current_line++;
 
@@ -637,8 +699,8 @@ int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
 
   if (buffer_len > 0 && current_ypos < max_ysize)
   {
-    DrawTextBuffer_Flush(x, y, buffer, font_nr, line_length, cut_length,
-                        mask_mode, centered, current_ypos);
+    DrawTextBuffer_Flush(x, y, buffer, base_font_nr, font_nr, line_length,
+                        cut_length, mask_mode, centered, current_ypos);
     current_ypos += line_height;
     current_line++;
   }
@@ -646,6 +708,39 @@ int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
   return current_line;
 }
 
+int DrawTextArea(int x, int y, char *text_buffer, int font_nr,
+                int line_length, int cut_length, int max_lines,
+                int line_spacing, int mask_mode, boolean autowrap,
+                boolean centered, boolean parse_comments)
+{
+  return DrawTextBufferExt(x, y, text_buffer, font_nr,
+                          line_length, cut_length, max_lines,
+                          line_spacing, mask_mode, autowrap,
+                          centered, parse_comments, TRUE);
+}
+
+int DrawTextBuffer(int x, int y, char *text_buffer, int font_nr,
+                  int line_length, int cut_length, int max_lines,
+                  int line_spacing, int mask_mode, boolean autowrap,
+                  boolean centered, boolean parse_comments)
+{
+  return DrawTextBufferExt(x, y, text_buffer, font_nr,
+                          line_length, cut_length, max_lines,
+                          line_spacing, mask_mode, autowrap,
+                          centered, parse_comments, FALSE);
+}
+
+int DrawTextBufferS(int x, int y, char *text_buffer, int font_nr,
+                   int line_length, int cut_length, int max_lines,
+                   int line_spacing, int mask_mode, boolean autowrap,
+                   boolean centered, boolean parse_comments)
+{
+  return DrawTextBuffer(gfx.sx + x, gfx.sy + y, text_buffer, font_nr,
+                       line_length, cut_length, max_lines,
+                       line_spacing, mask_mode, autowrap,
+                       centered, parse_comments);
+}
+
 int DrawTextBufferVA(int x, int y, char *format, va_list ap, int font_nr,
                     int line_length, int cut_length, int max_lines,
                     int line_spacing, int mask_mode, boolean autowrap,
index 407cb31a481e91bb90650985e16e147810246677..9295a037b7469ce6ebca8c1944898b81bfce6970 100644 (file)
                                 (c) == FONT_ASCII_DOWN      ? 111 :    \
                                 (c))
 
+#define MAP_FONT_ASCII_EXT(c)  ((c) == CHAR_BYTE_COPYRIGHT  ? 128 :    \
+                                (c) == CHAR_BYTE_UMLAUT_A   ? 129 :    \
+                                (c) == CHAR_BYTE_UMLAUT_O   ? 130 :    \
+                                (c) == CHAR_BYTE_UMLAUT_U   ? 131 :    \
+                                (c) == CHAR_BYTE_DEGREE     ? 132 :    \
+                                (c) == CHAR_BYTE_REGISTERED ? 133 :    \
+                                (c) == FONT_ASCII_CURSOR    ? 134 :    \
+                                (c) == CHAR_BYTE_UMLAUT_a   ? 135 :    \
+                                (c) == CHAR_BYTE_UMLAUT_o   ? 136 :    \
+                                (c) == CHAR_BYTE_UMLAUT_u   ? 137 :    \
+                                (c) == CHAR_BYTE_SHARP_S    ? 138 :    \
+                                (c) == FONT_ASCII_BUTTON    ? 141 :    \
+                                (c) == FONT_ASCII_UP        ? 142 :    \
+                                (c) == FONT_ASCII_DOWN      ? 143 :    \
+                                (c))
+
 // 64 regular ordered ASCII characters, 6 special characters, 1 cursor char.
 #define MIN_NUM_CHARS_PER_FONT                 64
+#define NUM_CHARS_PER_FONT_EXT                 112
 #define DEFAULT_NUM_CHARS_PER_FONT             (MIN_NUM_CHARS_PER_FONT + 6 +1)
 #define DEFAULT_NUM_CHARS_PER_LINE             16
 
 
 // font structure definitions
 
+void EnableDrawingText(void);
+void DisableDrawingText(void);
+
 void InitFontInfo(struct FontBitmapInfo *, int,
-                 int (*function1)(int), int (*function2)(char *));
+                 int (*function1)(int),
+                  int (*function2)(char *),
+                  char * (*function3)(int));
 void FreeFontInfo(struct FontBitmapInfo *);
 
 struct FontBitmapInfo *getFontBitmapInfo(int);
@@ -100,13 +122,16 @@ void DrawTextFCentered(int, int, char *, ...);
 void DrawTextS(int, int, int, char *);
 void DrawTextSCentered(int, int, char *);
 void DrawTextSAligned(int, int, char *, int, int);
-void DrawTextAligned(int, int, char *, int, int);
 void DrawText(int, int, char *, int);
 void DrawTextExt(DrawBuffer *, int, int, char *, int, int);
 
 char *GetTextBufferFromFile(char *, int);
+int DrawTextArea(int, int, char *, int, int, int, int, int, int,
+                boolean, boolean, boolean);
 int DrawTextBuffer(int, int, char *, int, int, int, int, int, int,
                   boolean, boolean, boolean);
+int DrawTextBufferS(int, int, char *, int, int, int, int, int, int,
+                   boolean, boolean, boolean);
 int DrawTextBufferVA(int, int, char *, va_list, int, int, int, int, int, int,
                     boolean, boolean, boolean);
 int DrawTextFile(int, int, char *, int, int, int, int, int, int,
index 62752f1fe8007ca150a4c3513a97c03e97cda56d..7dc2a7d4a2d1b7f3b666b37d4916ed17e428544f 100644 (file)
@@ -19,7 +19,7 @@
 #include <sys/types.h>
 
 
-#if !defined(PLATFORM_WIN32)
+#if !defined(PLATFORM_WINDOWS)
 typedef int boolean;
 typedef unsigned char byte;
 #endif
@@ -32,39 +32,69 @@ typedef unsigned char byte;
 #undef FALSE
 #endif
 
-#ifdef AUTO
-#undef AUTO
+#ifdef STATE_AUTO
+#undef STATE_AUTO
 #endif
 
-#define TRUE           1
-#define FALSE          0
-#define AUTO           -1
+#ifdef STATE_ASK
+#undef STATE_ASK
+#endif
+
+// values for boolean data type
+#define TRUE                   1
+#define FALSE                  0
+
+// values for 3-state data type (for "yes/no/auto" or "yes/no/ask")
+#define STATE_TRUE             1
+#define STATE_FALSE            0
+#define STATE_AUTO             -1
+#define STATE_ASK              -1
 
 #ifndef MIN
-#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#define MIN(a, b)              ((a) < (b) ? (a) : (b))
 #endif
 
 #ifndef MAX
-#define MAX(a,b)       ((a) > (b) ? (a) : (b))
+#define MAX(a, b)              ((a) > (b) ? (a) : (b))
 #endif
 
 #ifndef ABS
-#define ABS(a)         ((a) < 0 ? -(a) : (a))
+#define ABS(a)                 ((a) < 0 ? -(a) : (a))
 #endif
 
 #ifndef SIGN
-#define SIGN(a)                ((a) < 0 ? -1 : ((a) > 0 ? 1 : 0))
+#define SIGN(a)                        ((a) < 0 ? -1 : ((a) > 0 ? 1 : 0))
 #endif
 
 #ifndef ODD
-#define ODD(a)         (((a) & 1) == 1)
+#define ODD(a)                 (((a) & 1) == 1)
 #endif
 
 #ifndef EVEN
-#define EVEN(a)                (((a) & 1) == 0)
+#define EVEN(a)                        (((a) & 1) == 0)
 #endif
 
-#define ARRAY_SIZE(array)              (sizeof(array) / sizeof(array[0]))
+#define ARRAY_SIZE(array)      (sizeof(array) / sizeof(array[0]))
+
+#if defined(__x86_64__)
+
+#define PTR_TO_INT(p)          ((int) (long long) (p))
+#define PTR_TO_UINT(p)         ((unsigned int) (unsigned long long) (p))
+
+#define INT_TO_PTR(i)          ((void *) (long long) (i))
+#define UINT_TO_PTR(u)         ((void *) (unsigned long long) (u))
+
+#else
+
+#define PTR_TO_INT(p)          ((int) (long) (p))
+#define PTR_TO_UINT(p)         ((unsigned int) (unsigned long) (p))
+
+#define INT_TO_PTR(i)          ((void *) (long) (i))
+#define UINT_TO_PTR(u)         ((void *) (unsigned long) (u))
+
+#endif
+
+#define STRUCT_OFFSET(s, m)    (offsetof(s, m))
 
 
 struct ListNode
@@ -76,4 +106,11 @@ struct ListNode
 };
 typedef struct ListNode ListNode;
 
+struct DelayCounter
+{
+  unsigned int value;
+  unsigned int count;
+};
+typedef struct DelayCounter DelayCounter;
+
 #endif // TYPES_H
index 5b6fcc63ee27ce94849acd0e826da67ca701f1f6..0aa6347ac4106620b6c3d3aa851dd5b7f08e57ec 100644 (file)
@@ -45,11 +45,11 @@ long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, ui
 {
     uint32_t offset_truncated = 0;
     if (pfilefunc->zfile_func64.zseek64_file != NULL)
-        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque, filestream, offset, origin);
     offset_truncated = (uint32_t)offset;
     if (offset_truncated != offset)
         return -1;
-    return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream, offset_truncated, origin);
+    return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque, filestream, offset_truncated, origin);
 }
 
 uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream)
@@ -81,7 +81,6 @@ void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filef
     p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
 }
 
-static voidpf   ZCALLBACK fopen_file_func(ZIP_UNUSED voidpf opaque, const char *filename, int mode);
 static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
 static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size);
 static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream);
@@ -109,25 +108,6 @@ static voidpf file_build_ioposix(FILE *file, const char *filename)
     return (voidpf)ioposix;
 }
 
-static voidpf ZCALLBACK fopen_file_func(ZIP_UNUSED voidpf opaque, const char *filename, int mode)
-{
-    FILE* file = NULL;
-    const char *mode_fopen = NULL;
-    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
-        mode_fopen = "rb";
-    else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
-        mode_fopen = "r+b";
-    else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
-        mode_fopen = "wb";
-
-    if ((filename != NULL) && (mode_fopen != NULL))
-    {
-        file = fopen(filename, mode_fopen);
-        return file_build_ioposix(file, filename);
-    }
-    return file;
-}
-
 static voidpf ZCALLBACK fopen64_file_func(ZIP_UNUSED voidpf opaque, const void *filename, int mode)
 {
     FILE* file = NULL;
@@ -172,31 +152,6 @@ static voidpf ZCALLBACK fopendisk64_file_func(voidpf opaque, voidpf stream, uint
     return ret;
 }
 
-static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
-    FILE_IOPOSIX *ioposix = NULL;
-    char *diskFilename = NULL;
-    voidpf ret = NULL;
-    int i = 0;
-
-    if (stream == NULL)
-        return NULL;
-    ioposix = (FILE_IOPOSIX*)stream;
-    diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
-    strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
-    for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
-    {
-        if (diskFilename[i] != '.')
-            continue;
-        snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
-        break;
-    }
-    if (i >= 0)
-        ret = fopen_file_func(opaque, diskFilename, mode);
-    free(diskFilename);
-    return ret;
-}
-
 static uint32_t ZCALLBACK fread_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, void* buf, uint32_t size)
 {
     FILE_IOPOSIX *ioposix = NULL;
@@ -219,17 +174,6 @@ static uint32_t ZCALLBACK fwrite_file_func(ZIP_UNUSED voidpf opaque, voidpf stre
     return written;
 }
 
-static long ZCALLBACK ftell_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
-{
-    FILE_IOPOSIX *ioposix = NULL;
-    long ret = -1;
-    if (stream == NULL)
-        return ret;
-    ioposix = (FILE_IOPOSIX*)stream;
-    ret = ftell(ioposix->file);
-    return ret;
-}
-
 static uint64_t ZCALLBACK ftell64_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
 {
     FILE_IOPOSIX *ioposix = NULL;
@@ -241,35 +185,6 @@ static uint64_t ZCALLBACK ftell64_file_func(ZIP_UNUSED voidpf opaque, voidpf str
     return ret;
 }
 
-static long ZCALLBACK fseek_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, uint32_t offset, int origin)
-{
-    FILE_IOPOSIX *ioposix = NULL;
-    int fseek_origin = 0;
-    long ret = 0;
-
-    if (stream == NULL)
-        return -1;
-    ioposix = (FILE_IOPOSIX*)stream;
-
-    switch (origin)
-    {
-        case ZLIB_FILEFUNC_SEEK_CUR:
-            fseek_origin = SEEK_CUR;
-            break;
-        case ZLIB_FILEFUNC_SEEK_END:
-            fseek_origin = SEEK_END;
-            break;
-        case ZLIB_FILEFUNC_SEEK_SET:
-            fseek_origin = SEEK_SET;
-            break;
-        default:
-            return -1;
-    }
-    if (fseek(ioposix->file, offset, fseek_origin) != 0)
-        ret = -1;
-    return ret;
-}
-
 static long ZCALLBACK fseek64_file_func(ZIP_UNUSED voidpf opaque, voidpf stream, uint64_t offset, int origin)
 {
     FILE_IOPOSIX *ioposix = NULL;
@@ -326,19 +241,6 @@ static int ZCALLBACK ferror_file_func(ZIP_UNUSED voidpf opaque, voidpf stream)
     return ret;
 }
 
-void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
-{
-    pzlib_filefunc_def->zopen_file = fopen_file_func;
-    pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
-    pzlib_filefunc_def->zread_file = fread_file_func;
-    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
-    pzlib_filefunc_def->ztell_file = ftell_file_func;
-    pzlib_filefunc_def->zseek_file = fseek_file_func;
-    pzlib_filefunc_def->zclose_file = fclose_file_func;
-    pzlib_filefunc_def->zerror_file = ferror_file_func;
-    pzlib_filefunc_def->opaque = NULL;
-}
-
 void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
 {
     pzlib_filefunc_def->zopen64_file = fopen64_file_func;
index 4b21ef34eb8e97b91d500a2615a25723c6c4444b..1c70d61a19b7bcec15cd20429ebdc51421aaf2cf 100644 (file)
@@ -115,7 +115,6 @@ typedef struct zlib_filefunc64_def_s
     voidpf               opaque;
 } zlib_filefunc64_def;
 
-void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
 void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
 
 /* now internal definition, only for zip.c and unzip.h */
@@ -128,24 +127,24 @@ typedef struct zlib_filefunc64_32_def_s
     seek_file_func      zseek32_file;
 } zlib_filefunc64_32_def;
 
-#define ZREAD64(filefunc,filestream,buf,size)       ((*((filefunc).zfile_func64.zread_file))        ((filefunc).zfile_func64.opaque,filestream,buf,size))
-#define ZWRITE64(filefunc,filestream,buf,size)      ((*((filefunc).zfile_func64.zwrite_file))       ((filefunc).zfile_func64.opaque,filestream,buf,size))
-/*#define ZTELL64(filefunc,filestream)                ((*((filefunc).ztell64_file))                   ((filefunc).opaque,filestream))*/
-/*#define ZSEEK64(filefunc,filestream,pos,mode)       ((*((filefunc).zseek64_file))                   ((filefunc).opaque,filestream,pos,mode))*/
-#define ZCLOSE64(filefunc,filestream)               ((*((filefunc).zfile_func64.zclose_file))       ((filefunc).zfile_func64.opaque,filestream))
-#define ZERROR64(filefunc,filestream)               ((*((filefunc).zfile_func64.zerror_file))       ((filefunc).zfile_func64.opaque,filestream))
+#define ZREAD64(filefunc, filestream, buf, size)       ((*((filefunc).zfile_func64.zread_file))        ((filefunc).zfile_func64.opaque, filestream, buf, size))
+#define ZWRITE64(filefunc, filestream, buf, size)      ((*((filefunc).zfile_func64.zwrite_file))       ((filefunc).zfile_func64.opaque, filestream, buf, size))
+/*#define ZTELL64(filefunc, filestream)                ((*((filefunc).ztell64_file))                   ((filefunc).opaque, filestream))*/
+/*#define ZSEEK64(filefunc, filestream, pos, mode)       ((*((filefunc).zseek64_file))                   ((filefunc).opaque, filestream, pos, mode))*/
+#define ZCLOSE64(filefunc, filestream)               ((*((filefunc).zfile_func64.zclose_file))       ((filefunc).zfile_func64.opaque, filestream))
+#define ZERROR64(filefunc, filestream)               ((*((filefunc).zfile_func64.zerror_file))       ((filefunc).zfile_func64.opaque, filestream))
 
-voidpf   call_zopen64(const zlib_filefunc64_32_def *pfilefunc,const void*filename, int mode);
+voidpf   call_zopen64(const zlib_filefunc64_32_def *pfilefunc, const void *filename, int mode);
 voidpf   call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode);
 long     call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin);
 uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream);
 
 void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32);
 
-#define ZOPEN64(filefunc,filename,mode)             (call_zopen64((&(filefunc)),(filename),(mode)))
-#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
-#define ZTELL64(filefunc,filestream)                (call_ztell64((&(filefunc)),(filestream)))
-#define ZSEEK64(filefunc,filestream,pos,mode)       (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+#define ZOPEN64(filefunc, filename, mode)              (call_zopen64((&(filefunc)), (filename), (mode)))
+#define ZOPENDISK64(filefunc, filestream, diskn, mode) (call_zopendisk64((&(filefunc)), (filestream), (diskn), (mode)))
+#define ZTELL64(filefunc, filestream)                  (call_ztell64((&(filefunc)), (filestream)))
+#define ZSEEK64(filefunc, filestream, pos, mode)       (call_zseek64((&(filefunc)), (filestream), (pos), (mode)))
 
 #ifdef __cplusplus
 }
index 53a96e650cc5c965d1a14482fd58ef6bcb50d85a..0681294c68f1abc9693c19dbdbe8fc5b5eab5749 100644 (file)
@@ -37,7 +37,6 @@
 #  endif
 #endif
 
-voidpf   ZCALLBACK win32_open_file_func     (voidpf opaque, const char *filename, int mode);
 uint32_t ZCALLBACK win32_read_file_func     (voidpf opaque, voidpf stream, void* buf, uint32_t size);
 uint32_t ZCALLBACK win32_write_file_func    (voidpf opaque, voidpf stream, const void *buf, uint32_t size);
 uint64_t ZCALLBACK win32_tell64_file_func   (voidpf opaque, voidpf stream);
@@ -101,38 +100,6 @@ static voidpf win32_build_iowin(HANDLE hFile)
     return (voidpf)iowin;
 }
 
-static voidpf ZCALLBACK win32_open64_file_func(voidpf opaque, const void *filename, int mode)
-{
-    DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes;
-    HANDLE hFile = NULL;
-    WIN32FILE_IOWIN *iowin = NULL;
-
-    win32_translate_open_mode(mode, &dwDesiredAccess, &dwCreationDisposition, &dwShareMode, &dwFlagsAndAttributes);
-
-    if ((filename != NULL) && (dwDesiredAccess != 0))
-    {
-#ifdef IOWIN32_USING_WINRT_API
-#ifdef UNICODE
-        hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
-#else
-        WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
-        MultiByteToWideChar(CP_ACP, 0, (const char*)filename, -1, filenameW, FILENAME_MAX + 0x200);
-        hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
-#endif
-#else
-        hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
-#endif
-    }
-
-    iowin = win32_build_iowin(hFile);
-    if (iowin == NULL)
-        return NULL;
-    iowin->filenameLength = _tcslen(filename) + 1;
-    iowin->filename = (void*)malloc(iowin->filenameLength * sizeof(TCHAR));
-    _tcsncpy(iowin->filename, filename, iowin->filenameLength);
-    return iowin;
-}
-
 static voidpf ZCALLBACK win32_open64_file_funcA(voidpf opaque, const void *filename, int mode)
 {
     DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode, dwFlagsAndAttributes ;
@@ -161,117 +128,6 @@ static voidpf ZCALLBACK win32_open64_file_funcA(voidpf opaque, const void *filen
     return iowin;
 }
 
-static voidpf ZCALLBACK win32_open64_file_funcW(voidpf opaque, const void *filename, int mode)
-{
-    DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode, dwFlagsAndAttributes;
-    HANDLE hFile = NULL;
-    WIN32FILE_IOWIN *iowin = NULL;
-
-    win32_translate_open_mode(mode, &dwDesiredAccess, &dwCreationDisposition, &dwShareMode, &dwFlagsAndAttributes);
-
-    if ((filename != NULL) && (dwDesiredAccess != 0))
-    {
-#ifdef IOWIN32_USING_WINRT_API
-        hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
-#else
-        hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
-#endif
-    }
-
-    iowin = win32_build_iowin(hFile);
-    if (iowin == NULL)
-        return NULL;
-    if (iowin->filename == NULL)
-    {
-        iowin->filenameLength = wcslen(filename) + 1;
-        iowin->filename = (void*)malloc(iowin->filenameLength * sizeof(WCHAR));
-        wcsncpy(iowin->filename, filename, iowin->filenameLength);
-    }
-    return iowin;
-}
-
-voidpf ZCALLBACK win32_open_file_func(voidpf opaque, const char *filename, int mode)
-{
-    DWORD dwDesiredAccess, dwCreationDisposition, dwShareMode, dwFlagsAndAttributes ;
-    HANDLE hFile = NULL;
-    WIN32FILE_IOWIN *iowin = NULL;
-
-    win32_translate_open_mode(mode, &dwDesiredAccess, &dwCreationDisposition, &dwShareMode, &dwFlagsAndAttributes);
-
-    if ((filename != NULL) && (dwDesiredAccess != 0))
-    {
-#ifdef IOWIN32_USING_WINRT_API
-#ifdef UNICODE
-        hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
-#else
-        WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
-        MultiByteToWideChar(CP_ACP, 0, (const char*)filename, -1, filenameW, FILENAME_MAX + 0x200);
-        hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
-#endif
-#else
-        hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
-#endif
-    }
-
-    iowin = win32_build_iowin(hFile);
-    if (iowin == NULL)
-        return NULL;
-    iowin->filenameLength = _tcslen((TCHAR*)filename) + 1;
-    iowin->filename = (void*)malloc(iowin->filenameLength * sizeof(TCHAR));
-    _tcsncpy(iowin->filename, (TCHAR*)filename, iowin->filenameLength);
-    return iowin;
-}
-
-static voidpf ZCALLBACK win32_opendisk64_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
-    WIN32FILE_IOWIN *iowin = NULL;
-    TCHAR *diskFilename = NULL;
-    voidpf ret = NULL;
-    int i = 0;
-
-    if (stream == NULL)
-        return NULL;
-    iowin = (WIN32FILE_IOWIN*)stream;
-    diskFilename = (TCHAR*)malloc(iowin->filenameLength * sizeof(TCHAR));
-    _tcsncpy(diskFilename, iowin->filename, iowin->filenameLength);
-    for (i = iowin->filenameLength - 1; i >= 0; i -= 1)
-    {
-        if (diskFilename[i] != _T('.'))
-            continue;
-        _sntprintf(&diskFilename[i], iowin->filenameLength - i, _T(".z%02d"), number_disk + 1);
-        break;
-    }
-    if (i >= 0)
-        ret = win32_open64_file_func(opaque, (char*)diskFilename, mode);
-    free(diskFilename);
-    return ret;
-}
-
-static voidpf ZCALLBACK win32_opendisk64_file_funcW(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
-    WIN32FILE_IOWIN *iowin = NULL;
-    WCHAR *diskFilename = NULL;
-    voidpf ret = NULL;
-    int i = 0;
-
-    if (stream == NULL)
-        return NULL;
-    iowin = (WIN32FILE_IOWIN*)stream;
-    diskFilename = (WCHAR*)malloc((iowin->filenameLength + 10) * sizeof(WCHAR));
-    wcsncpy(diskFilename, iowin->filename, iowin->filenameLength);
-    for (i = iowin->filenameLength - 1; i >= 0; i -= 1)
-    {
-        if (diskFilename[i] != L'.')
-            continue;
-        _snwprintf(&diskFilename[i], (iowin->filenameLength + 10) - i, L".z%02d", number_disk + 1);
-        break;
-    }
-    if (i >= 0)
-        ret = win32_open64_file_funcW(opaque, diskFilename, mode);
-    free(diskFilename);
-    return ret;
-}
-
 static voidpf ZCALLBACK win32_opendisk64_file_funcA(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
 {
     WIN32FILE_IOWIN *iowin = NULL;
@@ -297,31 +153,6 @@ static voidpf ZCALLBACK win32_opendisk64_file_funcA(voidpf opaque, voidpf stream
     return ret;
 }
 
-static voidpf ZCALLBACK win32_opendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
-    WIN32FILE_IOWIN *iowin = NULL;
-    TCHAR *diskFilename = NULL;
-    voidpf ret = NULL;
-    int i = 0;
-
-    if (stream == NULL)
-        return NULL;
-    iowin = (WIN32FILE_IOWIN*)stream;
-    diskFilename = (TCHAR*)malloc(iowin->filenameLength * sizeof(TCHAR));
-    _tcsncpy(diskFilename, iowin->filename, iowin->filenameLength);
-    for (i = iowin->filenameLength - 1; i >= 0; i -= 1)
-    {
-        if (diskFilename[i] != _T('.'))
-            continue;
-        _sntprintf(&diskFilename[i], iowin->filenameLength - i, _T(".z%02d"), number_disk + 1);
-        break;
-    }
-    if (i >= 0)
-        ret = win32_open_file_func(opaque, (char*)diskFilename, mode);
-    free(diskFilename);
-    return ret;
-}
-
 uint32_t ZCALLBACK win32_read_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
 {
     DWORD ret = 0;
@@ -383,28 +214,6 @@ static BOOL win32_setfilepointer_internal(HANDLE hFile, LARGE_INTEGER pos, LARGE
 #endif
 }
 
-static long ZCALLBACK win32_tell_file_func(voidpf opaque, voidpf stream)
-{
-    long ret = -1;
-    HANDLE hFile = NULL;
-    if (stream != NULL)
-        hFile = ((WIN32FILE_IOWIN*)stream)->hf;
-    if (hFile != NULL)
-    {
-        LARGE_INTEGER pos;
-        pos.QuadPart = 0;
-        if (!win32_setfilepointer_internal(hFile, pos, &pos, FILE_CURRENT))
-        {
-            DWORD dwErr = GetLastError();
-            ((WIN32FILE_IOWIN*)stream)->error = (int)dwErr;
-            ret = -1;
-        }
-        else
-            ret = (long)pos.LowPart;
-    }
-    return ret;
-}
-
 uint64_t ZCALLBACK win32_tell64_file_func(voidpf opaque, voidpf stream)
 {
     uint64_t ret = (uint64_t)-1;
@@ -428,46 +237,6 @@ uint64_t ZCALLBACK win32_tell64_file_func(voidpf opaque, voidpf stream)
     return ret;
 }
 
-static long ZCALLBACK win32_seek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
-{
-    DWORD dwMoveMethod = 0xFFFFFFFF;
-    HANDLE hFile = NULL;
-    long ret = -1;
-
-    if (stream != NULL)
-        hFile = ((WIN32FILE_IOWIN*)stream)->hf;
-
-    switch (origin)
-    {
-        case ZLIB_FILEFUNC_SEEK_CUR:
-            dwMoveMethod = FILE_CURRENT;
-            break;
-        case ZLIB_FILEFUNC_SEEK_END:
-            dwMoveMethod = FILE_END;
-            break;
-        case ZLIB_FILEFUNC_SEEK_SET:
-            dwMoveMethod = FILE_BEGIN;
-            break;
-        default:
-            return -1;
-    }
-
-    if (hFile != NULL)
-    {
-        LARGE_INTEGER pos;
-        pos.QuadPart = offset;
-        if (!win32_setfilepointer_internal(hFile, pos, NULL, dwMoveMethod))
-        {
-            DWORD dwErr = GetLastError();
-            ((WIN32FILE_IOWIN*)stream)->error = (int)dwErr;
-            ret = -1;
-        }
-        else
-            ret = 0;
-    }
-    return ret;
-}
-
 long ZCALLBACK win32_seek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
 {
     DWORD dwMoveMethod = 0xFFFFFFFF;
@@ -536,32 +305,6 @@ int ZCALLBACK win32_error_file_func(voidpf opaque, voidpf stream)
     return ret;
 }
 
-void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
-{
-    pzlib_filefunc_def->zopen_file = win32_open_file_func;
-    pzlib_filefunc_def->zopendisk_file = win32_opendisk_file_func;
-    pzlib_filefunc_def->zread_file = win32_read_file_func;
-    pzlib_filefunc_def->zwrite_file = win32_write_file_func;
-    pzlib_filefunc_def->ztell_file = win32_tell_file_func;
-    pzlib_filefunc_def->zseek_file = win32_seek_file_func;
-    pzlib_filefunc_def->zclose_file = win32_close_file_func;
-    pzlib_filefunc_def->zerror_file = win32_error_file_func;
-    pzlib_filefunc_def->opaque = NULL;
-}
-
-void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def)
-{
-    pzlib_filefunc_def->zopen64_file = win32_open64_file_func;
-    pzlib_filefunc_def->zopendisk64_file = win32_opendisk64_file_func;
-    pzlib_filefunc_def->zread_file = win32_read_file_func;
-    pzlib_filefunc_def->zwrite_file = win32_write_file_func;
-    pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
-    pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
-    pzlib_filefunc_def->zclose_file = win32_close_file_func;
-    pzlib_filefunc_def->zerror_file = win32_error_file_func;
-    pzlib_filefunc_def->opaque = NULL;
-}
-
 void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def)
 {
     pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA;
@@ -575,17 +318,4 @@ void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def)
     pzlib_filefunc_def->opaque = NULL;
 }
 
-void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def)
-{
-    pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW;
-    pzlib_filefunc_def->zopendisk64_file = win32_opendisk64_file_funcW;
-    pzlib_filefunc_def->zread_file = win32_read_file_func;
-    pzlib_filefunc_def->zwrite_file = win32_write_file_func;
-    pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
-    pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
-    pzlib_filefunc_def->zclose_file = win32_close_file_func;
-    pzlib_filefunc_def->zerror_file = win32_error_file_func;
-    pzlib_filefunc_def->opaque = NULL;
-}
-
 #endif // _WIN32
index 7ce4fc9f35356213d14ebebc41b1702d660057a3..a6265ea397ac5b61a3357c26babc7cdee8fe7667 100644 (file)
 extern "C" {
 #endif
 
-void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
-void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def);
 void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def);
-void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def);
 
 #ifdef __cplusplus
 }
index cf9839b1bb6c2cb303467e05942181e4c63c8cb4..1ca632a96bb262f9069475f94eb7a8bc50824dac 100644 (file)
@@ -389,7 +389,7 @@ static int miniunz_extract_currentfile(unzFile uf, int opt_extract_without_path,
     err = unzGetCurrentFileInfo64(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
     if (err != UNZ_OK)
     {
-        debug_printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+        debug_printf("error %d with zipfile in unzGetCurrentFileInfo\n", err);
         return err;
     }
 
index 5f1cb151869f6846eac6bf45e6bb778712cc92ce..564d901df3adc18a90b3de40a7cbe15d6ce3a719 100644 (file)
@@ -122,8 +122,8 @@ typedef struct
     zlib_filefunc64_32_def z_filefunc;
 
     voidpf   filestream;                /* io structore of the zipfile */
-    uint16_t compression_method;        /* compression method (0==store) */
-    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (>0 for sfx) */
+    uint16_t compression_method;        /* compression method (0 == store) */
+    uint64_t byte_before_the_zipfile;   /* byte before the zipfile, (> 0 for sfx) */
     int      raw;
 } file_in_zip64_read_info_s;
 
index 4aa047ea165b201a03a7c008364539cadacc15c4..b457e18fad5875c48121e838b4b5c93e5e1728c5 100644 (file)
@@ -176,7 +176,7 @@ extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password
 
 extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
 /* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
-   if raw==1 *method will receive method of compression, *level will receive level of compression
+   if raw == 1 *method will receive method of compression, *level will receive level of compression
 
    NOTE: you can set level parameter as NULL (if you did not want known level,
          but you CANNOT set method parameter as NULL */
index 8dd3712b2d6b4488f851731deec7b082514ec9dd..8ab7313dba3a77667264417e627d886e78cd1035 100644 (file)
 #include "events.h"
 #include "config.h"
 
-Bitmap                *bitmap_db_field;
-Bitmap                *bitmap_db_panel;
-Bitmap                *bitmap_db_door_1;
-Bitmap                *bitmap_db_door_2;
-Bitmap                *bitmap_db_store_1;
-Bitmap                *bitmap_db_store_2;
-DrawBuffer            *fieldbuffer;
-DrawBuffer            *drawto_field;
+Bitmap                        *bitmap_db_field;
+Bitmap                        *bitmap_db_door_1;
+Bitmap                        *bitmap_db_door_2;
+Bitmap                        *bitmap_db_store_1;
+Bitmap                        *bitmap_db_store_2;
+DrawBuffer                    *fieldbuffer;
+DrawBuffer                    *drawto_field;
 
-int                    game_status = -1;
-int                    game_status_last_screen = -1;
-boolean                        level_editor_test_game = FALSE;
-boolean                        network_playing = FALSE;
+int                            game_status = -1;
+int                            game_status_last_screen = -1;
+boolean                                level_editor_test_game = FALSE;
+boolean                                score_info_tape_play = FALSE;
+boolean                                network_playing = FALSE;
 
-int                    key_joystick_mapping = 0;
+int                            key_joystick_mapping = 0;
 
-short                  Tile[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  Last[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-boolean                        Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-boolean                        Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  AmoebaCnt[MAX_NUM_AMOEBA];
-short                  AmoebaCnt2[MAX_NUM_AMOEBA];
-short                  ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          Tile[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          Last[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+boolean                                Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+boolean                                Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          AmoebaCnt[MAX_NUM_AMOEBA];
+short                          AmoebaCnt2[MAX_NUM_AMOEBA];
+short                          ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                          ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
-int                    GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-int                    GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxRandomStatic[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxElementEmpty[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                            GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
-int                    ActiveElement[MAX_NUM_ELEMENTS];
-int                    ActiveButton[NUM_IMAGE_FILES];
-int                    ActiveFont[NUM_FONTS];
+int                            ActiveElement[MAX_NUM_ELEMENTS];
+int                            ActiveButton[NUM_IMAGE_FILES];
+int                            ActiveFont[NUM_FONTS];
 
-int                    lev_fieldx, lev_fieldy;
-int                    scroll_x, scroll_y;
+int                            lev_fieldx, lev_fieldy;
+int                            scroll_x, scroll_y;
 
-int                    WIN_XSIZE = WIN_XSIZE_DEFAULT;
-int                    WIN_YSIZE = WIN_YSIZE_DEFAULT;
+int                            WIN_XSIZE = WIN_XSIZE_DEFAULT;
+int                            WIN_YSIZE = WIN_YSIZE_DEFAULT;
 
-int                    SCR_FIELDX = SCR_FIELDX_DEFAULT;
-int                    SCR_FIELDY = SCR_FIELDY_DEFAULT;
+int                            SCR_FIELDX = SCR_FIELDX_DEFAULT;
+int                            SCR_FIELDY = SCR_FIELDY_DEFAULT;
 
-int                    REAL_SX = 6, REAL_SY = 6;
-int                    SX = 8, SY = 8;
-int                    DX = 566, DY = 60;
-int                    VX = 566, VY = 400;
-int                    EX = 566, EY = 356;
-int                    dDX, dDY;
+int                            REAL_SX = 6, REAL_SY = 6;
+int                            SX = 8, SY = 8;
+int                            DX = 566, DY = 60;
+int                            VX = 566, VY = 400;
+int                            EX = 566, EY = 356;
+int                            dDX, dDY;
 
-int                    FULL_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
-int                    FULL_SYSIZE = 2 + SYSIZE_DEFAULT + 2;
-int                    SXSIZE = SXSIZE_DEFAULT;
-int                    SYSIZE = SYSIZE_DEFAULT;
+int                            FULL_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
+int                            FULL_SYSIZE = 2 + SYSIZE_DEFAULT + 2;
+int                            SXSIZE = SXSIZE_DEFAULT;
+int                            SYSIZE = SYSIZE_DEFAULT;
 
-int                    FADE_SX = 6, FADE_SY = 6;
-int                    FADE_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
-int                    FADE_SYSIZE = 2 + SXSIZE_DEFAULT + 2;
+int                            FADE_SX = 6, FADE_SY = 6;
+int                            FADE_SXSIZE = 2 + SXSIZE_DEFAULT + 2;
+int                            FADE_SYSIZE = 2 + SXSIZE_DEFAULT + 2;
 
-int                    DXSIZE = 100;
-int                    DYSIZE = 280;
-int                    VXSIZE = 100;
-int                    VYSIZE = 100;
-int                    EXSIZE = 100;
-int                    EYSIZE = 144;
-int                    TILESIZE_VAR = TILESIZE;
+int                            DXSIZE = 100;
+int                            DYSIZE = 280;
+int                            VXSIZE = 100;
+int                            VYSIZE = 100;
+int                            EXSIZE = 100;
+int                            EYSIZE = 144;
+int                            TILESIZE_VAR = TILESIZE;
 
-int                    FX, FY;
-int                    ScrollStepSize;
-int                    ScreenMovDir = MV_NONE, ScreenMovPos = 0;
-int                    ScreenGfxPos = 0;
-int                    BorderElement = EL_STEELWALL;
-int                    MenuFrameDelay = MENU_FRAME_DELAY;
-int                    GameFrameDelay = GAME_FRAME_DELAY;
-int                    FfwdFrameDelay = FFWD_FRAME_DELAY;
-int                    BX1, BY1;
-int                    BX2, BY2;
-int                    SBX_Left, SBX_Right;
-int                    SBY_Upper, SBY_Lower;
+int                            FX, FY;
+int                            ScrollStepSize;
+int                            ScreenMovDir = MV_NONE, ScreenMovPos = 0;
+int                            ScreenGfxPos = 0;
+int                            BorderElement = EL_STEELWALL;
+int                            MenuFrameDelay = MENU_FRAME_DELAY;
+int                            GameFrameDelay = GAME_FRAME_DELAY;
+int                            FfwdFrameDelay = FFWD_FRAME_DELAY;
+int                            BX1, BY1;
+int                            BX2, BY2;
+int                            SBX_Left, SBX_Right;
+int                            SBY_Upper, SBY_Lower;
 
-int                    TimeFrames, TimePlayed, TimeLeft, TapeTime;
+int                            TimeFrames, TimePlayed, TimeLeft;
+int                            TapeTimeFrames, TapeTime;
 
-boolean                        network_player_action_received = FALSE;
+boolean                                network_player_action_received = FALSE;
 
-struct LevelInfo       level, level_template;
-struct PlayerInfo      stored_player[MAX_PLAYERS], *local_player = NULL;
-struct ScoreInfo       scores, server_scores;
-struct TapeInfo                tape;
-struct GameInfo                game;
-struct GlobalInfo      global;
-struct BorderInfo      border;
-struct ViewportInfo    viewport;
-struct TitleFadingInfo fading;
-struct TitleFadingInfo title_initial_first_default;
-struct TitleFadingInfo title_initial_default;
-struct TitleFadingInfo title_first_default;
-struct TitleFadingInfo title_default;
-struct TitleMessageInfo        titlescreen_initial_first_default;
-struct TitleMessageInfo        titlescreen_initial_first[MAX_NUM_TITLE_IMAGES];
-struct TitleMessageInfo        titlescreen_initial_default;
-struct TitleMessageInfo        titlescreen_initial[MAX_NUM_TITLE_IMAGES];
-struct TitleMessageInfo        titlescreen_first_default;
-struct TitleMessageInfo        titlescreen_first[MAX_NUM_TITLE_IMAGES];
-struct TitleMessageInfo        titlescreen_default;
-struct TitleMessageInfo        titlescreen[MAX_NUM_TITLE_IMAGES];
-struct TitleMessageInfo        titlemessage_initial_first_default;
-struct TitleMessageInfo        titlemessage_initial_first[MAX_NUM_TITLE_MESSAGES];
-struct TitleMessageInfo        titlemessage_initial_default;
-struct TitleMessageInfo        titlemessage_initial[MAX_NUM_TITLE_MESSAGES];
-struct TitleMessageInfo        titlemessage_first_default;
-struct TitleMessageInfo        titlemessage_first[MAX_NUM_TITLE_MESSAGES];
-struct TitleMessageInfo        titlemessage_default;
-struct TitleMessageInfo        titlemessage[MAX_NUM_TITLE_MESSAGES];
-struct TitleMessageInfo        readme;
-struct InitInfo                init, init_last;
-struct MenuInfo                menu;
-struct DoorInfo                door_1, door_2;
-struct RequestInfo     request;
-struct PreviewInfo     preview;
-struct EditorInfo      editor;
+struct LevelInfo               level, level_template;
+struct PlayerInfo              stored_player[MAX_PLAYERS], *local_player = NULL;
+struct ScoreInfo               scores, server_scores;
+struct TapeInfo                        tape;
+struct GameInfo                        game;
+struct GlobalInfo              global;
+struct BorderInfo              border;
+struct ViewportInfo            viewport;
+struct TitleFadingInfo         fading;
+struct TitleFadingInfo         title_initial_first_default;
+struct TitleFadingInfo         title_initial_default;
+struct TitleFadingInfo         title_first_default;
+struct TitleFadingInfo         title_default;
+struct TitleMessageInfo                titlescreen_initial_first_default;
+struct TitleMessageInfo                titlescreen_initial_first[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo                titlescreen_initial_default;
+struct TitleMessageInfo                titlescreen_initial[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo                titlescreen_first_default;
+struct TitleMessageInfo                titlescreen_first[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo                titlescreen_default;
+struct TitleMessageInfo                titlescreen[MAX_NUM_TITLE_IMAGES];
+struct TitleMessageInfo                titlemessage_initial_first_default;
+struct TitleMessageInfo                titlemessage_initial_first[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo                titlemessage_initial_default;
+struct TitleMessageInfo                titlemessage_initial[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo                titlemessage_first_default;
+struct TitleMessageInfo                titlemessage_first[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo                titlemessage_default;
+struct TitleMessageInfo                titlemessage[MAX_NUM_TITLE_MESSAGES];
+struct TitleMessageInfo                readme;
+struct InitInfo                        init, init_last;
+struct MenuInfo                        menu;
+struct DoorInfo                        door_1, door_2;
+struct RequestInfo             request;
+struct PreviewInfo             preview;
+struct EditorInfo              editor;
 
-struct GraphicInfo     *graphic_info = NULL;
-struct SoundInfo       *sound_info = NULL;
-struct MusicInfo       *music_info = NULL;
-struct MusicFileInfo   *music_file_info = NULL;
-struct HelpAnimInfo    *helpanim_info = NULL;
+struct GraphicInfo            *graphic_info = NULL;
+struct SoundInfo              *sound_info = NULL;
+struct MusicInfo              *music_info = NULL;
+struct MusicFileInfo          *music_file_info = NULL;
+struct HelpAnimInfo           *helpanim_info = NULL;
 
-SetupFileHash          *helptext_info = NULL;
-SetupFileHash         *image_config_hash = NULL;
-SetupFileHash         *element_token_hash = NULL;
-SetupFileHash         *graphic_token_hash = NULL;
-SetupFileHash         *font_token_hash = NULL;
-SetupFileHash         *hide_setup_hash = NULL;
+SetupFileHash                 *helptext_info = NULL;
+SetupFileHash                 *image_config_hash = NULL;
+SetupFileHash                 *sound_config_hash = NULL;
+SetupFileHash                 *element_token_hash = NULL;
+SetupFileHash                 *graphic_token_hash = NULL;
+SetupFileHash                 *font_token_hash = NULL;
+SetupFileHash                 *hide_setup_hash = NULL;
+SetupFileHash                 *anim_url_hash = NULL;
 
 
 // ----------------------------------------------------------------------------
@@ -195,132 +200,132 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "empty_space",
     "empty_space",
-    "empty space"
+    "Empty space"
   },
   {
     "sand",
     "sand",
-    "sand"
+    "Sand"
   },
   {
     "wall",
     "wall",
-    "normal wall"
+    "Normal wall"
   },
   {
     "wall_slippery",
     "wall",
-    "slippery wall"
+    "Slippery wall"
   },
   {
     "rock",
     "rock",
-    "rock"
+    "Rock"
   },
   {
     "key_obsolete",
     "obsolete",
-    "key (OBSOLETE)"
+    "Key (obsolete)"
   },
   {
     "emerald",
     "emerald",
-    "emerald"
+    "Emerald"
   },
   {
     "exit_closed",
     "exit",
-    "closed exit"
+    "Closed exit"
   },
   {
     "player_obsolete",
     "obsolete",
-    "player (OBSOLETE)"
+    "Player (obsolete)"
   },
   {
     "bug",
     "bug",
-    "bug (random start direction)"
+    "Bug (random start direction)"
   },
   {
     "spaceship",
     "spaceship",
-    "spaceship (random start direction)"
+    "Spaceship (random start direction)"
   },
   {
     "yamyam",
     "yamyam",
-    "yam yam (random start direction)"
+    "Yam yam (random start direction)"
   },
   {
     "robot",
     "robot",
-    "robot"
+    "Robot"
   },
   {
     "steelwall",
     "steelwall",
-    "steel wall"
+    "Steel wall"
   },
   {
     "diamond",
     "diamond",
-    "diamond"
+    "Diamond"
   },
   {
     "amoeba_dead",
     "amoeba",
-    "dead amoeba"
+    "Dead amoeba"
   },
   {
     "quicksand_empty",
     "quicksand",
-    "quicksand (empty)"
+    "Quicksand (empty)"
   },
   {
     "quicksand_full",
     "quicksand",
-    "quicksand (with rock)"
+    "Quicksand (with rock)"
   },
   {
     "amoeba_drop",
     "amoeba",
-    "amoeba drop"
+    "Amoeba drop"
   },
   {
     "bomb",
     "bomb",
-    "bomb"
+    "Bomb"
   },
   {
     "magic_wall",
     "magic_wall",
-    "magic wall"
+    "Magic wall"
   },
   {
     "speed_pill",
     "speed_pill",
-    "speed pill"
+    "Speed pill"
   },
   {
     "acid",
     "acid",
-    "acid"
+    "Acid"
   },
   {
     "amoeba_wet",
     "amoeba",
-    "dropping amoeba (EM style)"
+    "Dropping amoeba (EM style)"
   },
   {
     "amoeba_dry",
     "amoeba",
-    "normal amoeba"
+    "Normal amoeba"
   },
   {
     "nut",
     "nut",
-    "nut with emerald"
+    "Nut with emerald"
   },
   {
     "game_of_life",
@@ -330,1212 +335,1212 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "biomaze",
     "biomaze",
-    "biomaze"
+    "Biomaze"
   },
   {
     "dynamite.active",
     "dynamite",
-    "burning dynamite"
+    "Burning dynamite"
   },
   {
     "stoneblock",
     "wall",
-    "wall"
+    "Wall"
   },
   {
     "robot_wheel",
     "robot_wheel",
-    "magic wheel"
+    "Magic wheel"
   },
   {
     "robot_wheel.active",
     "robot_wheel",
-    "magic wheel (running)"
+    "Magic wheel (running)"
   },
   {
     "key_1",
     "key",
-    "key 1"
+    "Key 1"
   },
   {
     "key_2",
     "key",
-    "key 2"
+    "Key 2"
   },
   {
     "key_3",
     "key",
-    "key 3"
+    "Key 3"
   },
   {
     "key_4",
     "key",
-    "key 4"
+    "Key 4"
   },
   {
     "gate_1",
     "gate",
-    "door 1"
+    "Door 1"
   },
   {
     "gate_2",
     "gate",
-    "door 2"
+    "Door 2"
   },
   {
     "gate_3",
     "gate",
-    "door 3"
+    "Door 3"
   },
   {
     "gate_4",
     "gate",
-    "door 4"
+    "Door 4"
   },
   {
     "gate_1_gray",
     "gate",
-    "gray door (opened by key 1)"
+    "Gray door (opened by key 1)"
   },
   {
     "gate_2_gray",
     "gate",
-    "gray door (opened by key 2)"
+    "Gray door (opened by key 2)"
   },
   {
     "gate_3_gray",
     "gate",
-    "gray door (opened by key 3)"
+    "Gray door (opened by key 3)"
   },
   {
     "gate_4_gray",
     "gate",
-    "gray door (opened by key 4)"
+    "Gray door (opened by key 4)"
   },
   {
     "dynamite",
     "dynamite",
-    "dynamite"
+    "Dynamite"
   },
   {
     "pacman",
     "pacman",
-    "pac man (random start direction)"
+    "Pac man (random start direction)"
   },
   {
     "invisible_wall",
     "wall",
-    "invisible normal wall"
+    "Invisible normal wall"
   },
   {
     "lamp",
     "lamp",
-    "lamp (off)"
+    "Lamp (off)"
   },
   {
     "lamp.active",
     "lamp",
-    "lamp (on)"
+    "Lamp (on)"
   },
   {
     "wall_emerald",
     "wall",
-    "wall with emerald"
+    "Wall with emerald"
   },
   {
     "wall_diamond",
     "wall",
-    "wall with diamond"
+    "Wall with diamond"
   },
   {
     "amoeba_full",
     "amoeba",
-    "amoeba with content"
+    "Amoeba with content"
   },
   {
     "bd_amoeba",
     "bd_amoeba",
-    "amoeba (BD style)"
+    "Amoeba (BD style)"
   },
   {
     "time_orb_full",
     "time_orb_full",
-    "time orb (full)"
+    "Time orb (full)"
   },
   {
     "time_orb_empty",
     "time_orb_empty",
-    "time orb (empty)"
+    "Time orb (empty)"
   },
   {
     "expandable_wall",
     "wall",
-    "growing wall (horizontal, visible)"
+    "Growing wall (horizontal, visible)"
   },
   {
     "bd_diamond",
     "bd_diamond",
-    "diamond (BD style)"
+    "Diamond (BD style)"
   },
   {
     "emerald_yellow",
     "emerald",
-    "yellow emerald"
+    "Yellow emerald"
   },
   {
     "wall_bd_diamond",
     "wall",
-    "wall with BD style diamond"
+    "Wall with BD style diamond"
   },
   {
     "wall_emerald_yellow",
     "wall",
-    "wall with yellow emerald"
+    "Wall with yellow emerald"
   },
   {
     "dark_yamyam",
     "dark_yamyam",
-    "dark yam yam"
+    "Dark yam yam"
   },
   {
     "bd_magic_wall",
     "bd_magic_wall",
-    "magic wall (BD style)"
+    "Magic wall (BD style)"
   },
   {
     "invisible_steelwall",
     "steelwall",
-    "invisible steel wall"
+    "Invisible steel wall"
   },
   {
     "sokoban_field_player",
     "sokoban",
-    "sokoban field with player"
+    "Sokoban field with player"
   },
   {
     "dynabomb_increase_number",
     "dynabomb",
-    "increases number of bombs"
+    "Increases number of bombs"
   },
   {
     "dynabomb_increase_size",
     "dynabomb",
-    "increases explosion size"
+    "Increases explosion size"
   },
   {
     "dynabomb_increase_power",
     "dynabomb",
-    "increases power of explosion"
+    "Increases power of explosion"
   },
   {
     "sokoban_object",
     "sokoban",
-    "sokoban object"
+    "Sokoban object"
   },
   {
     "sokoban_field_empty",
     "sokoban",
-    "sokoban empty field"
+    "Sokoban empty field"
   },
   {
     "sokoban_field_full",
     "sokoban",
-    "sokoban field with object"
+    "Sokoban field with object"
   },
   {
     "bd_butterfly.right",
     "bd_butterfly",
-    "butterfly (starts moving right)"
+    "Butterfly (starts moving right)"
   },
   {
     "bd_butterfly.up",
     "bd_butterfly",
-    "butterfly (starts moving up)"
+    "Butterfly (starts moving up)"
   },
   {
     "bd_butterfly.left",
     "bd_butterfly",
-    "butterfly (starts moving left)"
+    "Butterfly (starts moving left)"
   },
   {
     "bd_butterfly.down",
     "bd_butterfly",
-    "butterfly (starts moving down)"
+    "Butterfly (starts moving down)"
   },
   {
     "bd_firefly.right",
     "bd_firefly",
-    "firefly (starts moving right)"
+    "Firefly (starts moving right)"
   },
   {
     "bd_firefly.up",
     "bd_firefly",
-    "firefly (starts moving up)"
+    "Firefly (starts moving up)"
   },
   {
     "bd_firefly.left",
     "bd_firefly",
-    "firefly (starts moving left)"
+    "Firefly (starts moving left)"
   },
   {
     "bd_firefly.down",
     "bd_firefly",
-    "firefly (starts moving down)"
+    "Firefly (starts moving down)"
   },
   {
     "bd_butterfly",
     "bd_butterfly",
-    "butterfly (random start direction)"
+    "Butterfly (random start direction)"
   },
   {
     "bd_firefly",
     "bd_firefly",
-    "firefly (random start direction)"
+    "Firefly (random start direction)"
   },
   {
     "player_1",
     "player",
-    "player 1"
+    "Player 1"
   },
   {
     "player_2",
     "player",
-    "player 2"
+    "Player 2"
   },
   {
     "player_3",
     "player",
-    "player 3"
+    "Player 3"
   },
   {
     "player_4",
     "player",
-    "player 4"
+    "Player 4"
   },
   {
     "bug.right",
     "bug",
-    "bug (starts moving right)"
+    "Bug (starts moving right)"
   },
   {
     "bug.up",
     "bug",
-    "bug (starts moving up)"
+    "Bug (starts moving up)"
   },
   {
     "bug.left",
     "bug",
-    "bug (starts moving left)"
+    "Bug (starts moving left)"
   },
   {
     "bug.down",
     "bug",
-    "bug (starts moving down)"
+    "Bug (starts moving down)"
   },
   {
     "spaceship.right",
     "spaceship",
-    "spaceship (starts moving right)"
+    "Spaceship (starts moving right)"
   },
   {
     "spaceship.up",
     "spaceship",
-    "spaceship (starts moving up)"
+    "Spaceship (starts moving up)"
   },
   {
     "spaceship.left",
     "spaceship",
-    "spaceship (starts moving left)"
+    "Spaceship (starts moving left)"
   },
   {
     "spaceship.down",
     "spaceship",
-    "spaceship (starts moving down)"
+    "Spaceship (starts moving down)"
   },
   {
     "pacman.right",
     "pacman",
-    "pac man (starts moving right)"
+    "Pac man (starts moving right)"
   },
   {
     "pacman.up",
     "pacman",
-    "pac man (starts moving up)"
+    "Pac man (starts moving up)"
   },
   {
     "pacman.left",
     "pacman",
-    "pac man (starts moving left)"
+    "Pac man (starts moving left)"
   },
   {
     "pacman.down",
     "pacman",
-    "pac man (starts moving down)"
+    "Pac man (starts moving down)"
   },
   {
     "emerald_red",
     "emerald",
-    "red emerald"
+    "Red emerald"
   },
   {
     "emerald_purple",
     "emerald",
-    "purple emerald"
+    "Purple emerald"
   },
   {
     "wall_emerald_red",
     "wall",
-    "wall with red emerald"
+    "Wall with red emerald"
   },
   {
     "wall_emerald_purple",
     "wall",
-    "wall with purple emerald"
+    "Wall with purple emerald"
   },
   {
     "acid_pool_topleft",
     "wall",
-    "acid pool (top left)"
+    "Acid pool (top left)"
   },
   {
     "acid_pool_topright",
     "wall",
-    "acid pool (top right)"
+    "Acid pool (top right)"
   },
   {
     "acid_pool_bottomleft",
     "wall",
-    "acid pool (bottom left)"
+    "Acid pool (bottom left)"
   },
   {
     "acid_pool_bottom",
     "wall",
-    "acid pool (bottom)"
+    "Acid pool (bottom)"
   },
   {
     "acid_pool_bottomright",
     "wall",
-    "acid pool (bottom right)"
+    "Acid pool (bottom right)"
   },
   {
     "bd_wall",
     "wall",
-    "normal wall (BD style)"
+    "Normal wall (BD style)"
   },
   {
     "bd_rock",
     "bd_rock",
-    "rock (BD style)"
+    "Rock (BD style)"
   },
   {
     "exit_open",
     "exit",
-    "open exit"
+    "Open exit"
   },
   {
     "black_orb",
     "black_orb",
-    "black orb bomb"
+    "Black orb bomb"
   },
   {
     "amoeba_to_diamond",
     "amoeba",
-    "amoeba"
+    "Amoeba"
   },
   {
     "mole",
     "mole",
-    "mole (random start direction)"
+    "Mole (random start direction)"
   },
   {
     "penguin",
     "penguin",
-    "penguin"
+    "Penguin"
   },
   {
     "satellite",
     "satellite",
-    "satellite"
+    "Satellite"
   },
   {
     "arrow_left",
     "arrow",
-    "arrow left"
+    "Arrow left"
   },
   {
     "arrow_right",
     "arrow",
-    "arrow right"
+    "Arrow right"
   },
   {
     "arrow_up",
     "arrow",
-    "arrow up"
+    "Arrow up"
   },
   {
     "arrow_down",
     "arrow",
-    "arrow down"
+    "Arrow down"
   },
   {
     "pig",
     "pig",
-    "pig"
+    "Pig"
   },
   {
     "dragon",
     "dragon",
-    "fire breathing dragon"
+    "Fire breathing dragon"
   },
   {
     "em_key_1_file_obsolete",
     "obsolete",
-    "key (OBSOLETE)"
+    "Key (obsolete)"
   },
   {
     "char_space",
     "char",
-    "letter ' '"
+    "Letter ' '"
   },
   {
     "char_exclam",
     "char",
-    "letter '!'"
+    "Letter '!'"
   },
   {
     "char_quotedbl",
     "char",
-    "letter '\"'"
+    "Letter '\"'"
   },
   {
     "char_numbersign",
     "char",
-    "letter '#'"
+    "Letter '#'"
   },
   {
     "char_dollar",
     "char",
-    "letter '$'"
+    "Letter '$'"
   },
   {
     "char_percent",
     "char",
-    "letter '%'"
+    "Letter '%'"
   },
   {
     "char_ampersand",
     "char",
-    "letter '&'"
+    "Letter '&'"
   },
   {
     "char_apostrophe",
     "char",
-    "letter '''"
+    "Letter '''"
   },
   {
     "char_parenleft",
     "char",
-    "letter '('"
+    "Letter '('"
   },
   {
     "char_parenright",
     "char",
-    "letter ')'"
+    "Letter ')'"
   },
   {
     "char_asterisk",
     "char",
-    "letter '*'"
+    "Letter '*'"
   },
   {
     "char_plus",
     "char",
-    "letter '+'"
+    "Letter '+'"
   },
   {
     "char_comma",
     "char",
-    "letter ','"
+    "Letter ','"
   },
   {
     "char_minus",
     "char",
-    "letter '-'"
+    "Letter '-'"
   },
   {
     "char_period",
     "char",
-    "letter '.'"
+    "Letter '.'"
   },
   {
     "char_slash",
     "char",
-    "letter '/'"
+    "Letter '/'"
   },
   {
     "char_0",
     "char",
-    "letter '0'"
+    "Letter '0'"
   },
   {
     "char_1",
     "char",
-    "letter '1'"
+    "Letter '1'"
   },
   {
     "char_2",
     "char",
-    "letter '2'"
+    "Letter '2'"
   },
   {
     "char_3",
     "char",
-    "letter '3'"
+    "Letter '3'"
   },
   {
     "char_4",
     "char",
-    "letter '4'"
+    "Letter '4'"
   },
   {
     "char_5",
     "char",
-    "letter '5'"
+    "Letter '5'"
   },
   {
     "char_6",
     "char",
-    "letter '6'"
+    "Letter '6'"
   },
   {
     "char_7",
     "char",
-    "letter '7'"
+    "Letter '7'"
   },
   {
     "char_8",
     "char",
-    "letter '8'"
+    "Letter '8'"
   },
   {
     "char_9",
     "char",
-    "letter '9'"
+    "Letter '9'"
   },
   {
     "char_colon",
     "char",
-    "letter ':'"
+    "Letter ':'"
   },
   {
     "char_semicolon",
     "char",
-    "letter ';'"
+    "Letter ';'"
   },
   {
     "char_less",
     "char",
-    "letter '<'"
+    "Letter '<'"
   },
   {
     "char_equal",
     "char",
-    "letter '='"
+    "Letter '='"
   },
   {
     "char_greater",
     "char",
-    "letter '>'"
+    "Letter '>'"
   },
   {
     "char_question",
     "char",
-    "letter '?'"
+    "Letter '?'"
   },
   {
     "char_at",
     "char",
-    "letter '@'"
+    "Letter '@'"
   },
   {
     "char_a",
     "char",
-    "letter 'A'"
+    "Letter 'A'"
   },
   {
     "char_b",
     "char",
-    "letter 'B'"
+    "Letter 'B'"
   },
   {
     "char_c",
     "char",
-    "letter 'C'"
+    "Letter 'C'"
   },
   {
     "char_d",
     "char",
-    "letter 'D'"
+    "Letter 'D'"
   },
   {
     "char_e",
     "char",
-    "letter 'E'"
+    "Letter 'E'"
   },
   {
     "char_f",
     "char",
-    "letter 'F'"
+    "Letter 'F'"
   },
   {
     "char_g",
     "char",
-    "letter 'G'"
+    "Letter 'G'"
   },
   {
     "char_h",
     "char",
-    "letter 'H'"
+    "Letter 'H'"
   },
   {
     "char_i",
     "char",
-    "letter 'I'"
+    "Letter 'I'"
   },
   {
     "char_j",
     "char",
-    "letter 'J'"
+    "Letter 'J'"
   },
   {
     "char_k",
     "char",
-    "letter 'K'"
+    "Letter 'K'"
   },
   {
     "char_l",
     "char",
-    "letter 'L'"
+    "Letter 'L'"
   },
   {
     "char_m",
     "char",
-    "letter 'M'"
+    "Letter 'M'"
   },
   {
     "char_n",
     "char",
-    "letter 'N'"
+    "Letter 'N'"
   },
   {
     "char_o",
     "char",
-    "letter 'O'"
+    "Letter 'O'"
   },
   {
     "char_p",
     "char",
-    "letter 'P'"
+    "Letter 'P'"
   },
   {
     "char_q",
     "char",
-    "letter 'Q'"
+    "Letter 'Q'"
   },
   {
     "char_r",
     "char",
-    "letter 'R'"
+    "Letter 'R'"
   },
   {
     "char_s",
     "char",
-    "letter 'S'"
+    "Letter 'S'"
   },
   {
     "char_t",
     "char",
-    "letter 'T'"
+    "Letter 'T'"
   },
   {
     "char_u",
     "char",
-    "letter 'U'"
+    "Letter 'U'"
   },
   {
     "char_v",
     "char",
-    "letter 'V'"
+    "Letter 'V'"
   },
   {
     "char_w",
     "char",
-    "letter 'W'"
+    "Letter 'W'"
   },
   {
     "char_x",
     "char",
-    "letter 'X'"
+    "Letter 'X'"
   },
   {
     "char_y",
     "char",
-    "letter 'Y'"
+    "Letter 'Y'"
   },
   {
     "char_z",
     "char",
-    "letter 'Z'"
+    "Letter 'Z'"
   },
   {
     "char_bracketleft",
     "char",
-    "letter '['"
+    "Letter '['"
   },
   {
     "char_backslash",
     "char",
-    "letter '\\'"
+    "Letter '\\'"
   },
   {
     "char_bracketright",
     "char",
-    "letter ']'"
+    "Letter ']'"
   },
   {
     "char_asciicircum",
     "char",
-    "letter '^'"
+    "Letter '^'"
   },
   {
     "char_underscore",
     "char",
-    "letter '_'"
+    "Letter '_'"
   },
   {
     "char_copyright",
     "char",
-    "letter '\xa9'"
+    "Letter '\xa9'"
   },
   {
     "char_aumlaut",
     "char",
-    "letter '\xc4'"
+    "Letter '\xc4'"
   },
   {
     "char_oumlaut",
     "char",
-    "letter '\xd6'"
+    "Letter '\xd6'"
   },
   {
     "char_uumlaut",
     "char",
-    "letter '\xdc'"
+    "Letter '\xdc'"
   },
   {
     "char_degree",
     "char",
-    "letter '\xb0'"
+    "Letter '\xb0'"
   },
   {
     "char_trademark",
     "char",
-    "letter '\xae'"
+    "Letter '\xae'"
   },
   {
     "char_cursor",
     "char",
-    "letter '\xa0'"
+    "Letter '\xa0'"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_unused",
     "char",
-    "letter ''"
+    "Letter ''"
   },
   {
     "char_button",
     "char",
-    "letter 'button'"
+    "Letter 'button'"
   },
   {
     "char_up",
     "char",
-    "letter 'up'"
+    "Letter 'up'"
   },
   {
     "char_down",
     "char",
-    "letter 'down'"
+    "Letter 'down'"
   },
   {
     "expandable_wall_horizontal",
     "wall",
-    "growing wall (horizontal)"
+    "Growing wall (horizontal)"
   },
   {
     "expandable_wall_vertical",
     "wall",
-    "growing wall (vertical)"
+    "Growing wall (vertical)"
   },
   {
     "expandable_wall_any",
     "wall",
-    "growing wall (any direction)"
+    "Growing wall (any direction)"
   },
   {
     "em_gate_1",
     "gate",
-    "door 1 (EM style)"
+    "Door 1 (EM style)"
   },
   {
     "em_gate_2",
     "gate",
-    "door 2 (EM style)"
+    "Door 2 (EM style)"
   },
   {
     "em_gate_3",
     "gate",
-    "door 3 (EM style)"
+    "Door 3 (EM style)"
   },
   {
     "em_gate_4",
     "gate",
-    "door 4 (EM style)"
+    "Door 4 (EM style)"
   },
   {
     "em_key_2_file_obsolete",
     "obsolete",
-    "key (OBSOLETE)"
+    "Key (obsolete)"
   },
   {
     "em_key_3_file_obsolete",
     "obsolete",
-    "key (OBSOLETE)"
+    "Key (obsolete)"
   },
   {
     "em_key_4_file_obsolete",
     "obsolete",
-    "key (OBSOLETE)"
+    "Key (obsolete)"
   },
   {
     "sp_empty_space",
     "empty_space",
-    "empty space"
+    "Empty space"
   },
   {
     "sp_zonk",
     "sp_zonk",
-    "zonk"
+    "Zonk"
   },
   {
     "sp_base",
     "sp_base",
-    "base"
+    "Base"
   },
   {
     "sp_murphy",
     "player",
-    "murphy"
+    "Murphy"
   },
   {
     "sp_infotron",
     "sp_infotron",
-    "infotron"
+    "Infotron"
   },
   {
     "sp_chip_single",
     "wall",
-    "chip (single)"
+    "Chip (single)"
   },
   {
     "sp_hardware_gray",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_exit_closed",
     "sp_exit",
-    "exit"
+    "Exit"
   },
   {
     "sp_disk_orange",
     "sp_disk_orange",
-    "orange disk"
+    "Orange disk"
   },
   {
     "sp_port_right",
     "sp_port",
-    "port (leading right)"
+    "Port (leading right)"
   },
   {
     "sp_port_down",
     "sp_port",
-    "port (leading down)"
+    "Port (leading down)"
   },
   {
     "sp_port_left",
     "sp_port",
-    "port (leading left)"
+    "Port (leading left)"
   },
   {
     "sp_port_up",
     "sp_port",
-    "port (leading up)"
+    "Port (leading up)"
   },
   {
     "sp_gravity_port_right",
     "sp_gravity_port",
-    "gravity-on/off port (leading right)"
+    "Gravity-on/off port (leading right)"
   },
   {
     "sp_gravity_port_down",
     "sp_gravity_port",
-    "gravity-on/off port (leading down)"
+    "Gravity-on/off port (leading down)"
   },
   {
     "sp_gravity_port_left",
     "sp_gravity_port",
-    "gravity-on/off port (leading left)"
+    "Gravity-on/off port (leading left)"
   },
   {
     "sp_gravity_port_up",
     "sp_gravity_port",
-    "gravity-on/off port (leading up)"
+    "Gravity-on/off port (leading up)"
   },
   {
     "sp_sniksnak",
     "sp_sniksnak",
-    "snik snak"
+    "Snik snak"
   },
   {
     "sp_disk_yellow",
     "sp_disk_yellow",
-    "yellow disk"
+    "Yellow disk"
   },
   {
     "sp_terminal",
     "sp_terminal",
-    "terminal"
+    "Terminal"
   },
   {
     "sp_disk_red",
     "dynamite",
-    "red disk"
+    "Red disk"
   },
   {
     "sp_port_vertical",
     "sp_port",
-    "port (vertical)"
+    "Port (vertical)"
   },
   {
     "sp_port_horizontal",
     "sp_port",
-    "port (horizontal)"
+    "Port (horizontal)"
   },
   {
     "sp_port_any",
     "sp_port",
-    "port (any direction)"
+    "Port (any direction)"
   },
   {
     "sp_electron",
     "sp_electron",
-    "electron"
+    "Electron"
   },
   {
     "sp_buggy_base",
     "sp_buggy_base",
-    "buggy base"
+    "Buggy base"
   },
   {
     "sp_chip_left",
     "wall",
-    "chip (left half)"
+    "Chip (left half)"
   },
   {
     "sp_chip_right",
     "wall",
-    "chip (right half)"
+    "Chip (right half)"
   },
   {
     "sp_hardware_base_1",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_green",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_blue",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_red",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_yellow",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_base_2",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_base_3",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_base_4",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_base_5",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_hardware_base_6",
     "wall",
-    "hardware"
+    "Hardware"
   },
   {
     "sp_chip_top",
     "wall",
-    "chip (upper half)"
+    "Chip (upper half)"
   },
   {
     "sp_chip_bottom",
     "wall",
-    "chip (lower half)"
+    "Chip (lower half)"
   },
   {
     "em_gate_1_gray",
     "gate",
-    "gray door (EM style, key 1)"
+    "Gray door (EM style, key 1)"
   },
   {
     "em_gate_2_gray",
     "gate",
-    "gray door (EM style, key 2)"
+    "Gray door (EM style, key 2)"
   },
   {
     "em_gate_3_gray",
     "gate",
-    "gray door (EM style, key 3)"
+    "Gray door (EM style, key 3)"
   },
   {
     "em_gate_4_gray",
     "gate",
-    "gray door (EM style, key 4)"
+    "Gray door (EM style, key 4)"
   },
   {
     "em_dynamite",
     "dynamite",
-    "dynamite (EM style)"
+    "Dynamite (EM style)"
   },
   {
     "em_dynamite.active",
     "dynamite",
-    "burning dynamite (EM style)"
+    "Burning dynamite (EM style)"
   },
   {
     "pearl",
     "pearl",
-    "pearl"
+    "Pearl"
   },
   {
     "crystal",
     "crystal",
-    "crystal"
+    "Crystal"
   },
   {
     "wall_pearl",
     "wall",
-    "wall with pearl"
+    "Wall with pearl"
   },
   {
     "wall_crystal",
     "wall",
-    "wall with crystal"
+    "Wall with crystal"
   },
   {
     "dc_gate_white",
     "gate",
-    "white door"
+    "White door"
   },
   {
     "dc_gate_white_gray",
     "gate",
-    "gray door (opened by white key)"
+    "Gray door (opened by white key)"
   },
   {
     "dc_key_white",
     "key",
-    "white key"
+    "White key"
   },
   {
     "shield_normal",
     "shield_normal",
-    "shield (normal)"
+    "Shield (normal)"
   },
   {
     "extra_time",
     "extra_time",
-    "extra time"
+    "Extra time"
   },
   {
     "switchgate_open",
     "switchgate",
-    "switch gate (open)"
+    "Switch gate (open)"
   },
   {
     "switchgate_closed",
     "switchgate",
-    "switch gate (closed)"
+    "Switch gate (closed)"
   },
   {
     "switchgate_switch_up",
     "switchgate_switch",
-    "switch for switch gate"
+    "Switch for switch gate"
   },
   {
     "switchgate_switch_down",
     "switchgate_switch",
-    "switch for switch gate"
+    "Switch for switch gate"
   },
   {
     "unused_269",
@@ -1550,242 +1555,242 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "conveyor_belt_1_left",
     "conveyor_belt",
-    "conveyor belt 1 (left)"
+    "Conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_middle",
     "conveyor_belt",
-    "conveyor belt 1 (middle)"
+    "Conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_right",
     "conveyor_belt",
-    "conveyor belt 1 (right)"
+    "Conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_1_switch_left",
     "conveyor_belt_switch",
-    "switch for conveyor belt 1 (left)"
+    "Switch for conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_switch_middle",
     "conveyor_belt_switch",
-    "switch for conveyor belt 1 (middle)"
+    "Switch for conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_switch_right",
     "conveyor_belt_switch",
-    "switch for conveyor belt 1 (right)"
+    "Switch for conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_2_left",
     "conveyor_belt",
-    "conveyor belt 2 (left)"
+    "Conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_middle",
     "conveyor_belt",
-    "conveyor belt 2 (middle)"
+    "Conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_right",
     "conveyor_belt",
-    "conveyor belt 2 (right)"
+    "Conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_2_switch_left",
     "conveyor_belt_switch",
-    "switch for conveyor belt 2 (left)"
+    "Switch for conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_switch_middle",
     "conveyor_belt_switch",
-    "switch for conveyor belt 2 (middle)"
+    "Switch for conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_switch_right",
     "conveyor_belt_switch",
-    "switch for conveyor belt 2 (right)"
+    "Switch for conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_3_left",
     "conveyor_belt",
-    "conveyor belt 3 (left)"
+    "Conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_middle",
     "conveyor_belt",
-    "conveyor belt 3 (middle)"
+    "Conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_right",
     "conveyor_belt",
-    "conveyor belt 3 (right)"
+    "Conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_3_switch_left",
     "conveyor_belt_switch",
-    "switch for conveyor belt 3 (left)"
+    "Switch for conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_switch_middle",
     "conveyor_belt_switch",
-    "switch for conveyor belt 3 (middle)"
+    "Switch for conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_switch_right",
     "conveyor_belt_switch",
-    "switch for conveyor belt 3 (right)"
+    "Switch for conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_4_left",
     "conveyor_belt",
-    "conveyor belt 4 (left)"
+    "Conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_middle",
     "conveyor_belt",
-    "conveyor belt 4 (middle)"
+    "Conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_right",
     "conveyor_belt",
-    "conveyor belt 4 (right)"
+    "Conveyor belt 4 (right)"
   },
   {
     "conveyor_belt_4_switch_left",
     "conveyor_belt_switch",
-    "switch for conveyor belt 4 (left)"
+    "Switch for conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_switch_middle",
     "conveyor_belt_switch",
-    "switch for conveyor belt 4 (middle)"
+    "Switch for conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_switch_right",
     "conveyor_belt_switch",
-    "switch for conveyor belt 4 (right)"
+    "Switch for conveyor belt 4 (right)"
   },
   {
     "landmine",
     "landmine",
-    "land mine (not removable)"
+    "Land mine (not removable)"
   },
   {
     "envelope_obsolete",
     "obsolete",
-    "envelope (OBSOLETE)"
+    "Envelope (obsolete)"
   },
   {
     "light_switch",
     "light_switch",
-    "light switch (off)"
+    "Light switch (off)"
   },
   {
     "light_switch.active",
     "light_switch",
-    "light switch (on)"
+    "Light switch (on)"
   },
   {
     "sign_exclamation",
     "sign",
-    "sign (exclamation)"
+    "Sign (exclamation)"
   },
   {
     "sign_radioactivity",
     "sign",
-    "sign (radio activity)"
+    "Sign (radio activity)"
   },
   {
     "sign_stop",
     "sign",
-    "sign (stop)"
+    "Sign (stop)"
   },
   {
     "sign_wheelchair",
     "sign",
-    "sign (wheel chair)"
+    "Sign (wheel chair)"
   },
   {
     "sign_parking",
     "sign",
-    "sign (parking)"
+    "Sign (parking)"
   },
   {
     "sign_no_entry",
     "sign",
-    "sign (no entry)"
+    "Sign (no entry)"
   },
   {
     "sign_unused_1",
     "sign",
-    "sign (unused)"
+    "Sign (unused)"
   },
   {
     "sign_give_way",
     "sign",
-    "sign (give way)"
+    "Sign (give way)"
   },
   {
     "sign_entry_forbidden",
     "sign",
-    "sign (entry forbidden)"
+    "Sign (entry forbidden)"
   },
   {
     "sign_emergency_exit",
     "sign",
-    "sign (emergency exit)"
+    "Sign (emergency exit)"
   },
   {
     "sign_yin_yang",
     "sign",
-    "sign (yin yang)"
+    "Sign (yin yang)"
   },
   {
     "sign_unused_2",
     "sign",
-    "sign (unused)"
+    "Sign (unused)"
   },
   {
     "mole.left",
     "mole",
-    "mole (starts moving left)"
+    "Mole (starts moving left)"
   },
   {
     "mole.right",
     "mole",
-    "mole (starts moving right)"
+    "Mole (starts moving right)"
   },
   {
     "mole.up",
     "mole",
-    "mole (starts moving up)"
+    "Mole (starts moving up)"
   },
   {
     "mole.down",
     "mole",
-    "mole (starts moving down)"
+    "Mole (starts moving down)"
   },
   {
     "steelwall_slippery",
     "steelwall",
-    "slippery steel wall"
+    "Slippery steel wall"
   },
   {
     "invisible_sand",
     "sand",
-    "invisible sand"
+    "Invisible sand"
   },
   {
     "dx_unknown_15",
     "unknown",
-    "dx unknown element 15"
+    "DX unknown element 15"
   },
   {
     "dx_unknown_42",
     "unknown",
-    "dx unknown element 42"
+    "DX unknown element 42"
   },
   {
     "unused_319",
@@ -1800,187 +1805,187 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "shield_deadly",
     "shield_deadly",
-    "shield (deadly, kills enemies)"
+    "Shield (deadly, kills enemies)"
   },
   {
     "timegate_open",
     "timegate",
-    "time gate (open)"
+    "Time gate (open)"
   },
   {
     "timegate_closed",
     "timegate",
-    "time gate (closed)"
+    "Time gate (closed)"
   },
   {
     "timegate_switch.active",
     "timegate_switch",
-    "switch for time gate"
+    "Switch for time gate"
   },
   {
     "timegate_switch",
     "timegate_switch",
-    "switch for time gate"
+    "Switch for time gate"
   },
   {
     "balloon",
     "balloon",
-    "balloon"
+    "Balloon"
   },
   {
     "balloon_switch_left",
     "balloon_switch",
-    "wind switch (left)"
+    "Wind switch (left)"
   },
   {
     "balloon_switch_right",
     "balloon_switch",
-    "wind switch (right)"
+    "Wind switch (right)"
   },
   {
     "balloon_switch_up",
     "balloon_switch",
-    "wind switch (up)"
+    "Wind switch (up)"
   },
   {
     "balloon_switch_down",
     "balloon_switch",
-    "wind switch (down)"
+    "Wind switch (down)"
   },
   {
     "balloon_switch_any",
     "balloon_switch",
-    "wind switch (any direction)"
+    "Wind switch (any direction)"
   },
   {
     "emc_steelwall_1",
     "steelwall",
-    "steel wall 1 (EMC style)"
+    "Steel wall 1 (EMC style)"
   },
   {
     "emc_steelwall_2",
     "steelwall",
-    "steel wall 2 (EMC style)"
+    "Steel wall 2 (EMC style)"
   },
   {
     "emc_steelwall_3",
     "steelwall",
-    "steel wall 3 (EMC style)"
+    "Steel wall 3 (EMC style)"
   },
   {
     "emc_steelwall_4",
     "steelwall",
-    "steel wall 4 (EMC style)"
+    "Steel wall 4 (EMC style)"
   },
   {
     "emc_wall_1",
     "wall",
-    "normal wall 1 (EMC style)"
+    "Normal wall 1 (EMC style)"
   },
   {
     "emc_wall_2",
     "wall",
-    "normal wall 2 (EMC style)"
+    "Normal wall 2 (EMC style)"
   },
   {
     "emc_wall_3",
     "wall",
-    "normal wall 3 (EMC style)"
+    "Normal wall 3 (EMC style)"
   },
   {
     "emc_wall_4",
     "wall",
-    "normal wall 4 (EMC style)"
+    "Normal wall 4 (EMC style)"
   },
   {
     "emc_wall_5",
     "wall",
-    "normal wall 5 (EMC style)"
+    "Normal wall 5 (EMC style)"
   },
   {
     "emc_wall_6",
     "wall",
-    "normal wall 6 (EMC style)"
+    "Normal wall 6 (EMC style)"
   },
   {
     "emc_wall_7",
     "wall",
-    "normal wall 7 (EMC style)"
+    "Normal wall 7 (EMC style)"
   },
   {
     "emc_wall_8",
     "wall",
-    "normal wall 8 (EMC style)"
+    "Normal wall 8 (EMC style)"
   },
   {
     "tube_any",
     "tube",
-    "tube (any direction)"
+    "Tube (any direction)"
   },
   {
     "tube_vertical",
     "tube",
-    "tube (vertical)"
+    "Tube (vertical)"
   },
   {
     "tube_horizontal",
     "tube",
-    "tube (horizontal)"
+    "Tube (horizontal)"
   },
   {
     "tube_vertical_left",
     "tube",
-    "tube (vertical & left)"
+    "Tube (vertical & left)"
   },
   {
     "tube_vertical_right",
     "tube",
-    "tube (vertical & right)"
+    "Tube (vertical & right)"
   },
   {
     "tube_horizontal_up",
     "tube",
-    "tube (horizontal & up)"
+    "Tube (horizontal & up)"
   },
   {
     "tube_horizontal_down",
     "tube",
-    "tube (horizontal & down)"
+    "Tube (horizontal & down)"
   },
   {
     "tube_left_up",
     "tube",
-    "tube (left & up)"
+    "Tube (left & up)"
   },
   {
     "tube_left_down",
     "tube",
-    "tube (left & down)"
+    "Tube (left & down)"
   },
   {
     "tube_right_up",
     "tube",
-    "tube (right & up)"
+    "Tube (right & up)"
   },
   {
     "tube_right_down",
     "tube",
-    "tube (right & down)"
+    "Tube (right & down)"
   },
   {
     "spring",
     "spring",
-    "spring"
+    "Spring"
   },
   {
     "trap",
     "trap",
-    "trap"
+    "Trap"
   },
   {
     "dx_supabomb",
     "bomb",
-    "stable bomb (DX style)"
+    "Stable bomb (DX style)"
   },
   {
     "unused_358",
@@ -1995,1727 +2000,1727 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "custom_1",
     "custom",
-    "custom element 1"
+    "Custom element 1"
   },
   {
     "custom_2",
     "custom",
-    "custom element 2"
+    "Custom element 2"
   },
   {
     "custom_3",
     "custom",
-    "custom element 3"
+    "Custom element 3"
   },
   {
     "custom_4",
     "custom",
-    "custom element 4"
+    "Custom element 4"
   },
   {
     "custom_5",
     "custom",
-    "custom element 5"
+    "Custom element 5"
   },
   {
     "custom_6",
     "custom",
-    "custom element 6"
+    "Custom element 6"
   },
   {
     "custom_7",
     "custom",
-    "custom element 7"
+    "Custom element 7"
   },
   {
     "custom_8",
     "custom",
-    "custom element 8"
+    "Custom element 8"
   },
   {
     "custom_9",
     "custom",
-    "custom element 9"
+    "Custom element 9"
   },
   {
     "custom_10",
     "custom",
-    "custom element 10"
+    "Custom element 10"
   },
   {
     "custom_11",
     "custom",
-    "custom element 11"
+    "Custom element 11"
   },
   {
     "custom_12",
     "custom",
-    "custom element 12"
+    "Custom element 12"
   },
   {
     "custom_13",
     "custom",
-    "custom element 13"
+    "Custom element 13"
   },
   {
     "custom_14",
     "custom",
-    "custom element 14"
+    "Custom element 14"
   },
   {
     "custom_15",
     "custom",
-    "custom element 15"
+    "Custom element 15"
   },
   {
     "custom_16",
     "custom",
-    "custom element 16"
+    "Custom element 16"
   },
   {
     "custom_17",
     "custom",
-    "custom element 17"
+    "Custom element 17"
   },
   {
     "custom_18",
     "custom",
-    "custom element 18"
+    "Custom element 18"
   },
   {
     "custom_19",
     "custom",
-    "custom element 19"
+    "Custom element 19"
   },
   {
     "custom_20",
     "custom",
-    "custom element 20"
+    "Custom element 20"
   },
   {
     "custom_21",
     "custom",
-    "custom element 21"
+    "Custom element 21"
   },
   {
     "custom_22",
     "custom",
-    "custom element 22"
+    "Custom element 22"
   },
   {
     "custom_23",
     "custom",
-    "custom element 23"
+    "Custom element 23"
   },
   {
     "custom_24",
     "custom",
-    "custom element 24"
+    "Custom element 24"
   },
   {
     "custom_25",
     "custom",
-    "custom element 25"
+    "Custom element 25"
   },
   {
     "custom_26",
     "custom",
-    "custom element 26"
+    "Custom element 26"
   },
   {
     "custom_27",
     "custom",
-    "custom element 27"
+    "Custom element 27"
   },
   {
     "custom_28",
     "custom",
-    "custom element 28"
+    "Custom element 28"
   },
   {
     "custom_29",
     "custom",
-    "custom element 29"
+    "Custom element 29"
   },
   {
     "custom_30",
     "custom",
-    "custom element 30"
+    "Custom element 30"
   },
   {
     "custom_31",
     "custom",
-    "custom element 31"
+    "Custom element 31"
   },
   {
     "custom_32",
     "custom",
-    "custom element 32"
+    "Custom element 32"
   },
   {
     "custom_33",
     "custom",
-    "custom element 33"
+    "Custom element 33"
   },
   {
     "custom_34",
     "custom",
-    "custom element 34"
+    "Custom element 34"
   },
   {
     "custom_35",
     "custom",
-    "custom element 35"
+    "Custom element 35"
   },
   {
     "custom_36",
     "custom",
-    "custom element 36"
+    "Custom element 36"
   },
   {
     "custom_37",
     "custom",
-    "custom element 37"
+    "Custom element 37"
   },
   {
     "custom_38",
     "custom",
-    "custom element 38"
+    "Custom element 38"
   },
   {
     "custom_39",
     "custom",
-    "custom element 39"
+    "Custom element 39"
   },
   {
     "custom_40",
     "custom",
-    "custom element 40"
+    "Custom element 40"
   },
   {
     "custom_41",
     "custom",
-    "custom element 41"
+    "Custom element 41"
   },
   {
     "custom_42",
     "custom",
-    "custom element 42"
+    "Custom element 42"
   },
   {
     "custom_43",
     "custom",
-    "custom element 43"
+    "Custom element 43"
   },
   {
     "custom_44",
     "custom",
-    "custom element 44"
+    "Custom element 44"
   },
   {
     "custom_45",
     "custom",
-    "custom element 45"
+    "Custom element 45"
   },
   {
     "custom_46",
     "custom",
-    "custom element 46"
+    "Custom element 46"
   },
   {
     "custom_47",
     "custom",
-    "custom element 47"
+    "Custom element 47"
   },
   {
     "custom_48",
     "custom",
-    "custom element 48"
+    "Custom element 48"
   },
   {
     "custom_49",
     "custom",
-    "custom element 49"
+    "Custom element 49"
   },
   {
     "custom_50",
     "custom",
-    "custom element 50"
+    "Custom element 50"
   },
   {
     "custom_51",
     "custom",
-    "custom element 51"
+    "Custom element 51"
   },
   {
     "custom_52",
     "custom",
-    "custom element 52"
+    "Custom element 52"
   },
   {
     "custom_53",
     "custom",
-    "custom element 53"
+    "Custom element 53"
   },
   {
     "custom_54",
     "custom",
-    "custom element 54"
+    "Custom element 54"
   },
   {
     "custom_55",
     "custom",
-    "custom element 55"
+    "Custom element 55"
   },
   {
     "custom_56",
     "custom",
-    "custom element 56"
+    "Custom element 56"
   },
   {
     "custom_57",
     "custom",
-    "custom element 57"
+    "Custom element 57"
   },
   {
     "custom_58",
     "custom",
-    "custom element 58"
+    "Custom element 58"
   },
   {
     "custom_59",
     "custom",
-    "custom element 59"
+    "Custom element 59"
   },
   {
     "custom_60",
     "custom",
-    "custom element 60"
+    "Custom element 60"
   },
   {
     "custom_61",
     "custom",
-    "custom element 61"
+    "Custom element 61"
   },
   {
     "custom_62",
     "custom",
-    "custom element 62"
+    "Custom element 62"
   },
   {
     "custom_63",
     "custom",
-    "custom element 63"
+    "Custom element 63"
   },
   {
     "custom_64",
     "custom",
-    "custom element 64"
+    "Custom element 64"
   },
   {
     "custom_65",
     "custom",
-    "custom element 65"
+    "Custom element 65"
   },
   {
     "custom_66",
     "custom",
-    "custom element 66"
+    "Custom element 66"
   },
   {
     "custom_67",
     "custom",
-    "custom element 67"
+    "Custom element 67"
   },
   {
     "custom_68",
     "custom",
-    "custom element 68"
+    "Custom element 68"
   },
   {
     "custom_69",
     "custom",
-    "custom element 69"
+    "Custom element 69"
   },
   {
     "custom_70",
     "custom",
-    "custom element 70"
+    "Custom element 70"
   },
   {
     "custom_71",
     "custom",
-    "custom element 71"
+    "Custom element 71"
   },
   {
     "custom_72",
     "custom",
-    "custom element 72"
+    "Custom element 72"
   },
   {
     "custom_73",
     "custom",
-    "custom element 73"
+    "Custom element 73"
   },
   {
     "custom_74",
     "custom",
-    "custom element 74"
+    "Custom element 74"
   },
   {
     "custom_75",
     "custom",
-    "custom element 75"
+    "Custom element 75"
   },
   {
     "custom_76",
     "custom",
-    "custom element 76"
+    "Custom element 76"
   },
   {
     "custom_77",
     "custom",
-    "custom element 77"
+    "Custom element 77"
   },
   {
     "custom_78",
     "custom",
-    "custom element 78"
+    "Custom element 78"
   },
   {
     "custom_79",
     "custom",
-    "custom element 79"
+    "Custom element 79"
   },
   {
     "custom_80",
     "custom",
-    "custom element 80"
+    "Custom element 80"
   },
   {
     "custom_81",
     "custom",
-    "custom element 81"
+    "Custom element 81"
   },
   {
     "custom_82",
     "custom",
-    "custom element 82"
+    "Custom element 82"
   },
   {
     "custom_83",
     "custom",
-    "custom element 83"
+    "Custom element 83"
   },
   {
     "custom_84",
     "custom",
-    "custom element 84"
+    "Custom element 84"
   },
   {
     "custom_85",
     "custom",
-    "custom element 85"
+    "Custom element 85"
   },
   {
     "custom_86",
     "custom",
-    "custom element 86"
+    "Custom element 86"
   },
   {
     "custom_87",
     "custom",
-    "custom element 87"
+    "Custom element 87"
   },
   {
     "custom_88",
     "custom",
-    "custom element 88"
+    "Custom element 88"
   },
   {
     "custom_89",
     "custom",
-    "custom element 89"
+    "Custom element 89"
   },
   {
     "custom_90",
     "custom",
-    "custom element 90"
+    "Custom element 90"
   },
   {
     "custom_91",
     "custom",
-    "custom element 91"
+    "Custom element 91"
   },
   {
     "custom_92",
     "custom",
-    "custom element 92"
+    "Custom element 92"
   },
   {
     "custom_93",
     "custom",
-    "custom element 93"
+    "Custom element 93"
   },
   {
     "custom_94",
     "custom",
-    "custom element 94"
+    "Custom element 94"
   },
   {
     "custom_95",
     "custom",
-    "custom element 95"
+    "Custom element 95"
   },
   {
     "custom_96",
     "custom",
-    "custom element 96"
+    "Custom element 96"
   },
   {
     "custom_97",
     "custom",
-    "custom element 97"
+    "Custom element 97"
   },
   {
     "custom_98",
     "custom",
-    "custom element 98"
+    "Custom element 98"
   },
   {
     "custom_99",
     "custom",
-    "custom element 99"
+    "Custom element 99"
   },
   {
     "custom_100",
     "custom",
-    "custom element 100"
+    "Custom element 100"
   },
   {
     "custom_101",
     "custom",
-    "custom element 101"
+    "Custom element 101"
   },
   {
     "custom_102",
     "custom",
-    "custom element 102"
+    "Custom element 102"
   },
   {
     "custom_103",
     "custom",
-    "custom element 103"
+    "Custom element 103"
   },
   {
     "custom_104",
     "custom",
-    "custom element 104"
+    "Custom element 104"
   },
   {
     "custom_105",
     "custom",
-    "custom element 105"
+    "Custom element 105"
   },
   {
     "custom_106",
     "custom",
-    "custom element 106"
+    "Custom element 106"
   },
   {
     "custom_107",
     "custom",
-    "custom element 107"
+    "Custom element 107"
   },
   {
     "custom_108",
     "custom",
-    "custom element 108"
+    "Custom element 108"
   },
   {
     "custom_109",
     "custom",
-    "custom element 109"
+    "Custom element 109"
   },
   {
     "custom_110",
     "custom",
-    "custom element 110"
+    "Custom element 110"
   },
   {
     "custom_111",
     "custom",
-    "custom element 111"
+    "Custom element 111"
   },
   {
     "custom_112",
     "custom",
-    "custom element 112"
+    "Custom element 112"
   },
   {
     "custom_113",
     "custom",
-    "custom element 113"
+    "Custom element 113"
   },
   {
     "custom_114",
     "custom",
-    "custom element 114"
+    "Custom element 114"
   },
   {
     "custom_115",
     "custom",
-    "custom element 115"
+    "Custom element 115"
   },
   {
     "custom_116",
     "custom",
-    "custom element 116"
+    "Custom element 116"
   },
   {
     "custom_117",
     "custom",
-    "custom element 117"
+    "Custom element 117"
   },
   {
     "custom_118",
     "custom",
-    "custom element 118"
+    "Custom element 118"
   },
   {
     "custom_119",
     "custom",
-    "custom element 119"
+    "Custom element 119"
   },
   {
     "custom_120",
     "custom",
-    "custom element 120"
+    "Custom element 120"
   },
   {
     "custom_121",
     "custom",
-    "custom element 121"
+    "Custom element 121"
   },
   {
     "custom_122",
     "custom",
-    "custom element 122"
+    "Custom element 122"
   },
   {
     "custom_123",
     "custom",
-    "custom element 123"
+    "Custom element 123"
   },
   {
     "custom_124",
     "custom",
-    "custom element 124"
+    "Custom element 124"
   },
   {
     "custom_125",
     "custom",
-    "custom element 125"
+    "Custom element 125"
   },
   {
     "custom_126",
     "custom",
-    "custom element 126"
+    "Custom element 126"
   },
   {
     "custom_127",
     "custom",
-    "custom element 127"
+    "Custom element 127"
   },
   {
     "custom_128",
     "custom",
-    "custom element 128"
+    "Custom element 128"
   },
   {
     "custom_129",
     "custom",
-    "custom element 129"
+    "Custom element 129"
   },
   {
     "custom_130",
     "custom",
-    "custom element 130"
+    "Custom element 130"
   },
   {
     "custom_131",
     "custom",
-    "custom element 131"
+    "Custom element 131"
   },
   {
     "custom_132",
     "custom",
-    "custom element 132"
+    "Custom element 132"
   },
   {
     "custom_133",
     "custom",
-    "custom element 133"
+    "Custom element 133"
   },
   {
     "custom_134",
     "custom",
-    "custom element 134"
+    "Custom element 134"
   },
   {
     "custom_135",
     "custom",
-    "custom element 135"
+    "Custom element 135"
   },
   {
     "custom_136",
     "custom",
-    "custom element 136"
+    "Custom element 136"
   },
   {
     "custom_137",
     "custom",
-    "custom element 137"
+    "Custom element 137"
   },
   {
     "custom_138",
     "custom",
-    "custom element 138"
+    "Custom element 138"
   },
   {
     "custom_139",
     "custom",
-    "custom element 139"
+    "Custom element 139"
   },
   {
     "custom_140",
     "custom",
-    "custom element 140"
+    "Custom element 140"
   },
   {
     "custom_141",
     "custom",
-    "custom element 141"
+    "Custom element 141"
   },
   {
     "custom_142",
     "custom",
-    "custom element 142"
+    "Custom element 142"
   },
   {
     "custom_143",
     "custom",
-    "custom element 143"
+    "Custom element 143"
   },
   {
     "custom_144",
     "custom",
-    "custom element 144"
+    "Custom element 144"
   },
   {
     "custom_145",
     "custom",
-    "custom element 145"
+    "Custom element 145"
   },
   {
     "custom_146",
     "custom",
-    "custom element 146"
+    "Custom element 146"
   },
   {
     "custom_147",
     "custom",
-    "custom element 147"
+    "Custom element 147"
   },
   {
     "custom_148",
     "custom",
-    "custom element 148"
+    "Custom element 148"
   },
   {
     "custom_149",
     "custom",
-    "custom element 149"
+    "Custom element 149"
   },
   {
     "custom_150",
     "custom",
-    "custom element 150"
+    "Custom element 150"
   },
   {
     "custom_151",
     "custom",
-    "custom element 151"
+    "Custom element 151"
   },
   {
     "custom_152",
     "custom",
-    "custom element 152"
+    "Custom element 152"
   },
   {
     "custom_153",
     "custom",
-    "custom element 153"
+    "Custom element 153"
   },
   {
     "custom_154",
     "custom",
-    "custom element 154"
+    "Custom element 154"
   },
   {
     "custom_155",
     "custom",
-    "custom element 155"
+    "Custom element 155"
   },
   {
     "custom_156",
     "custom",
-    "custom element 156"
+    "Custom element 156"
   },
   {
     "custom_157",
     "custom",
-    "custom element 157"
+    "Custom element 157"
   },
   {
     "custom_158",
     "custom",
-    "custom element 158"
+    "Custom element 158"
   },
   {
     "custom_159",
     "custom",
-    "custom element 159"
+    "Custom element 159"
   },
   {
     "custom_160",
     "custom",
-    "custom element 160"
+    "Custom element 160"
   },
   {
     "custom_161",
     "custom",
-    "custom element 161"
+    "Custom element 161"
   },
   {
     "custom_162",
     "custom",
-    "custom element 162"
+    "Custom element 162"
   },
   {
     "custom_163",
     "custom",
-    "custom element 163"
+    "Custom element 163"
   },
   {
     "custom_164",
     "custom",
-    "custom element 164"
+    "Custom element 164"
   },
   {
     "custom_165",
     "custom",
-    "custom element 165"
+    "Custom element 165"
   },
   {
     "custom_166",
     "custom",
-    "custom element 166"
+    "Custom element 166"
   },
   {
     "custom_167",
     "custom",
-    "custom element 167"
+    "Custom element 167"
   },
   {
     "custom_168",
     "custom",
-    "custom element 168"
+    "Custom element 168"
   },
   {
     "custom_169",
     "custom",
-    "custom element 169"
+    "Custom element 169"
   },
   {
     "custom_170",
     "custom",
-    "custom element 170"
+    "Custom element 170"
   },
   {
     "custom_171",
     "custom",
-    "custom element 171"
+    "Custom element 171"
   },
   {
     "custom_172",
     "custom",
-    "custom element 172"
+    "Custom element 172"
   },
   {
     "custom_173",
     "custom",
-    "custom element 173"
+    "Custom element 173"
   },
   {
     "custom_174",
     "custom",
-    "custom element 174"
+    "Custom element 174"
   },
   {
     "custom_175",
     "custom",
-    "custom element 175"
+    "Custom element 175"
   },
   {
     "custom_176",
     "custom",
-    "custom element 176"
+    "Custom element 176"
   },
   {
     "custom_177",
     "custom",
-    "custom element 177"
+    "Custom element 177"
   },
   {
     "custom_178",
     "custom",
-    "custom element 178"
+    "Custom element 178"
   },
   {
     "custom_179",
     "custom",
-    "custom element 179"
+    "Custom element 179"
   },
   {
     "custom_180",
     "custom",
-    "custom element 180"
+    "Custom element 180"
   },
   {
     "custom_181",
     "custom",
-    "custom element 181"
+    "Custom element 181"
   },
   {
     "custom_182",
     "custom",
-    "custom element 182"
+    "Custom element 182"
   },
   {
     "custom_183",
     "custom",
-    "custom element 183"
+    "Custom element 183"
   },
   {
     "custom_184",
     "custom",
-    "custom element 184"
+    "Custom element 184"
   },
   {
     "custom_185",
     "custom",
-    "custom element 185"
+    "Custom element 185"
   },
   {
     "custom_186",
     "custom",
-    "custom element 186"
+    "Custom element 186"
   },
   {
     "custom_187",
     "custom",
-    "custom element 187"
+    "Custom element 187"
   },
   {
     "custom_188",
     "custom",
-    "custom element 188"
+    "Custom element 188"
   },
   {
     "custom_189",
     "custom",
-    "custom element 189"
+    "Custom element 189"
   },
   {
     "custom_190",
     "custom",
-    "custom element 190"
+    "Custom element 190"
   },
   {
     "custom_191",
     "custom",
-    "custom element 191"
+    "Custom element 191"
   },
   {
     "custom_192",
     "custom",
-    "custom element 192"
+    "Custom element 192"
   },
   {
     "custom_193",
     "custom",
-    "custom element 193"
+    "Custom element 193"
   },
   {
     "custom_194",
     "custom",
-    "custom element 194"
+    "Custom element 194"
   },
   {
     "custom_195",
     "custom",
-    "custom element 195"
+    "Custom element 195"
   },
   {
     "custom_196",
     "custom",
-    "custom element 196"
+    "Custom element 196"
   },
   {
     "custom_197",
     "custom",
-    "custom element 197"
+    "Custom element 197"
   },
   {
     "custom_198",
     "custom",
-    "custom element 198"
+    "Custom element 198"
   },
   {
     "custom_199",
     "custom",
-    "custom element 199"
+    "Custom element 199"
   },
   {
     "custom_200",
     "custom",
-    "custom element 200"
+    "Custom element 200"
   },
   {
     "custom_201",
     "custom",
-    "custom element 201"
+    "Custom element 201"
   },
   {
     "custom_202",
     "custom",
-    "custom element 202"
+    "Custom element 202"
   },
   {
     "custom_203",
     "custom",
-    "custom element 203"
+    "Custom element 203"
   },
   {
     "custom_204",
     "custom",
-    "custom element 204"
+    "Custom element 204"
   },
   {
     "custom_205",
     "custom",
-    "custom element 205"
+    "Custom element 205"
   },
   {
     "custom_206",
     "custom",
-    "custom element 206"
+    "Custom element 206"
   },
   {
     "custom_207",
     "custom",
-    "custom element 207"
+    "Custom element 207"
   },
   {
     "custom_208",
     "custom",
-    "custom element 208"
+    "Custom element 208"
   },
   {
     "custom_209",
     "custom",
-    "custom element 209"
+    "Custom element 209"
   },
   {
     "custom_210",
     "custom",
-    "custom element 210"
+    "Custom element 210"
   },
   {
     "custom_211",
     "custom",
-    "custom element 211"
+    "Custom element 211"
   },
   {
     "custom_212",
     "custom",
-    "custom element 212"
+    "Custom element 212"
   },
   {
     "custom_213",
     "custom",
-    "custom element 213"
+    "Custom element 213"
   },
   {
     "custom_214",
     "custom",
-    "custom element 214"
+    "Custom element 214"
   },
   {
     "custom_215",
     "custom",
-    "custom element 215"
+    "Custom element 215"
   },
   {
     "custom_216",
     "custom",
-    "custom element 216"
+    "Custom element 216"
   },
   {
     "custom_217",
     "custom",
-    "custom element 217"
+    "Custom element 217"
   },
   {
     "custom_218",
     "custom",
-    "custom element 218"
+    "Custom element 218"
   },
   {
     "custom_219",
     "custom",
-    "custom element 219"
+    "Custom element 219"
   },
   {
     "custom_220",
     "custom",
-    "custom element 220"
+    "Custom element 220"
   },
   {
     "custom_221",
     "custom",
-    "custom element 221"
+    "Custom element 221"
   },
   {
     "custom_222",
     "custom",
-    "custom element 222"
+    "Custom element 222"
   },
   {
     "custom_223",
     "custom",
-    "custom element 223"
+    "Custom element 223"
   },
   {
     "custom_224",
     "custom",
-    "custom element 224"
+    "Custom element 224"
   },
   {
     "custom_225",
     "custom",
-    "custom element 225"
+    "Custom element 225"
   },
   {
     "custom_226",
     "custom",
-    "custom element 226"
+    "Custom element 226"
   },
   {
     "custom_227",
     "custom",
-    "custom element 227"
+    "Custom element 227"
   },
   {
     "custom_228",
     "custom",
-    "custom element 228"
+    "Custom element 228"
   },
   {
     "custom_229",
     "custom",
-    "custom element 229"
+    "Custom element 229"
   },
   {
     "custom_230",
     "custom",
-    "custom element 230"
+    "Custom element 230"
   },
   {
     "custom_231",
     "custom",
-    "custom element 231"
+    "Custom element 231"
   },
   {
     "custom_232",
     "custom",
-    "custom element 232"
+    "Custom element 232"
   },
   {
     "custom_233",
     "custom",
-    "custom element 233"
+    "Custom element 233"
   },
   {
     "custom_234",
     "custom",
-    "custom element 234"
+    "Custom element 234"
   },
   {
     "custom_235",
     "custom",
-    "custom element 235"
+    "Custom element 235"
   },
   {
     "custom_236",
     "custom",
-    "custom element 236"
+    "Custom element 236"
   },
   {
     "custom_237",
     "custom",
-    "custom element 237"
+    "Custom element 237"
   },
   {
     "custom_238",
     "custom",
-    "custom element 238"
+    "Custom element 238"
   },
   {
     "custom_239",
     "custom",
-    "custom element 239"
+    "Custom element 239"
   },
   {
     "custom_240",
     "custom",
-    "custom element 240"
+    "Custom element 240"
   },
   {
     "custom_241",
     "custom",
-    "custom element 241"
+    "Custom element 241"
   },
   {
     "custom_242",
     "custom",
-    "custom element 242"
+    "Custom element 242"
   },
   {
     "custom_243",
     "custom",
-    "custom element 243"
+    "Custom element 243"
   },
   {
     "custom_244",
     "custom",
-    "custom element 244"
+    "Custom element 244"
   },
   {
     "custom_245",
     "custom",
-    "custom element 245"
+    "Custom element 245"
   },
   {
     "custom_246",
     "custom",
-    "custom element 246"
+    "Custom element 246"
   },
   {
     "custom_247",
     "custom",
-    "custom element 247"
+    "Custom element 247"
   },
   {
     "custom_248",
     "custom",
-    "custom element 248"
+    "Custom element 248"
   },
   {
     "custom_249",
     "custom",
-    "custom element 249"
+    "Custom element 249"
   },
   {
     "custom_250",
     "custom",
-    "custom element 250"
+    "Custom element 250"
   },
   {
     "custom_251",
     "custom",
-    "custom element 251"
+    "Custom element 251"
   },
   {
     "custom_252",
     "custom",
-    "custom element 252"
+    "Custom element 252"
   },
   {
     "custom_253",
     "custom",
-    "custom element 253"
+    "Custom element 253"
   },
   {
     "custom_254",
     "custom",
-    "custom element 254"
+    "Custom element 254"
   },
   {
     "custom_255",
     "custom",
-    "custom element 255"
+    "Custom element 255"
   },
   {
     "custom_256",
     "custom",
-    "custom element 256"
+    "Custom element 256"
   },
   {
     "em_key_1",
     "key",
-    "key 1 (EM style)"
+    "Key 1 (EM style)"
     },
   {
     "em_key_2",
     "key",
-    "key 2 (EM style)"
+    "Key 2 (EM style)"
     },
   {
     "em_key_3",
     "key",
-    "key 3 (EM style)"
+    "Key 3 (EM style)"
   },
   {
     "em_key_4",
     "key",
-    "key 4 (EM style)"
+    "Key 4 (EM style)"
   },
   {
     "envelope_1",
     "envelope",
-    "mail envelope 1"
+    "Mail envelope 1"
   },
   {
     "envelope_2",
     "envelope",
-    "mail envelope 2"
+    "Mail envelope 2"
   },
   {
     "envelope_3",
     "envelope",
-    "mail envelope 3"
+    "Mail envelope 3"
   },
   {
     "envelope_4",
     "envelope",
-    "mail envelope 4"
+    "Mail envelope 4"
   },
   {
     "group_1",
     "group",
-    "group element 1"
+    "Group element 1"
   },
   {
     "group_2",
     "group",
-    "group element 2"
+    "Group element 2"
   },
   {
     "group_3",
     "group",
-    "group element 3"
+    "Group element 3"
   },
   {
     "group_4",
     "group",
-    "group element 4"
+    "Group element 4"
   },
   {
     "group_5",
     "group",
-    "group element 5"
+    "Group element 5"
   },
   {
     "group_6",
     "group",
-    "group element 6"
+    "Group element 6"
   },
   {
     "group_7",
     "group",
-    "group element 7"
+    "Group element 7"
   },
   {
     "group_8",
     "group",
-    "group element 8"
+    "Group element 8"
   },
   {
     "group_9",
     "group",
-    "group element 9"
+    "Group element 9"
   },
   {
     "group_10",
     "group",
-    "group element 10"
+    "Group element 10"
   },
   {
     "group_11",
     "group",
-    "group element 11"
+    "Group element 11"
   },
   {
     "group_12",
     "group",
-    "group element 12"
+    "Group element 12"
   },
   {
     "group_13",
     "group",
-    "group element 13"
+    "Group element 13"
   },
   {
     "group_14",
     "group",
-    "group element 14"
+    "Group element 14"
   },
   {
     "group_15",
     "group",
-    "group element 15"
+    "Group element 15"
   },
   {
     "group_16",
     "group",
-    "group element 16"
+    "Group element 16"
   },
   {
     "group_17",
     "group",
-    "group element 17"
+    "Group element 17"
   },
   {
     "group_18",
     "group",
-    "group element 18"
+    "Group element 18"
   },
   {
     "group_19",
     "group",
-    "group element 19"
+    "Group element 19"
   },
   {
     "group_20",
     "group",
-    "group element 20"
+    "Group element 20"
   },
   {
     "group_21",
     "group",
-    "group element 21"
+    "Group element 21"
   },
   {
     "group_22",
     "group",
-    "group element 22"
+    "Group element 22"
   },
   {
     "group_23",
     "group",
-    "group element 23"
+    "Group element 23"
   },
   {
     "group_24",
     "group",
-    "group element 24"
+    "Group element 24"
   },
   {
     "group_25",
     "group",
-    "group element 25"
+    "Group element 25"
   },
   {
     "group_26",
     "group",
-    "group element 26"
+    "Group element 26"
   },
   {
     "group_27",
     "group",
-    "group element 27"
+    "Group element 27"
   },
   {
     "group_28",
     "group",
-    "group element 28"
+    "Group element 28"
   },
   {
     "group_29",
     "group",
-    "group element 29"
+    "Group element 29"
   },
   {
     "group_30",
     "group",
-    "group element 30"
+    "Group element 30"
   },
   {
     "group_31",
     "group",
-    "group element 31"
+    "Group element 31"
   },
   {
     "group_32",
     "group",
-    "group element 32"
+    "Group element 32"
   },
   {
     "unknown",
     "unknown",
-    "unknown element"
+    "Unknown element"
   },
   {
     "trigger_element",
     "trigger",
-    "element triggering change"
+    "Element triggering change"
   },
   {
     "trigger_player",
     "trigger",
-    "player triggering change"
+    "Player triggering change"
   },
   {
     "sp_gravity_on_port_right",
     "sp_gravity_on_port",
-    "gravity-on port (leading right)"
+    "Gravity-on port (leading right)"
   },
   {
     "sp_gravity_on_port_down",
     "sp_gravity_on_port",
-    "gravity-on port (leading down)"
+    "Gravity-on port (leading down)"
   },
   {
     "sp_gravity_on_port_left",
     "sp_gravity_on_port",
-    "gravity-on port (leading left)"
+    "Gravity-on port (leading left)"
   },
   {
     "sp_gravity_on_port_up",
     "sp_gravity_on_port",
-    "gravity-on port (leading up)"
+    "Gravity-on port (leading up)"
   },
   {
     "sp_gravity_off_port_right",
     "sp_gravity_off_port",
-    "gravity-off port (leading right)"
+    "Gravity-off port (leading right)"
   },
   {
     "sp_gravity_off_port_down",
     "sp_gravity_off_port",
-    "gravity-off port (leading down)"
+    "Gravity-off port (leading down)"
   },
   {
     "sp_gravity_off_port_left",
     "sp_gravity_off_port",
-    "gravity-off port (leading left)"
+    "Gravity-off port (leading left)"
   },
   {
     "sp_gravity_off_port_up",
     "sp_gravity_off_port",
-    "gravity-off port (leading up)"
+    "Gravity-off port (leading up)"
   },
   {
     "balloon_switch_none",
     "balloon_switch",
-    "wind switch (off)"
+    "Wind switch (off)"
   },
   {
     "emc_gate_5",
     "gate",
-    "door 5 (EMC style)",
+    "Door 5 (EMC style)",
   },
   {
     "emc_gate_6",
     "gate",
-    "door 6 (EMC style)",
+    "Door 6 (EMC style)",
   },
   {
     "emc_gate_7",
     "gate",
-    "door 7 (EMC style)",
+    "Door 7 (EMC style)",
   },
   {
     "emc_gate_8",
     "gate",
-    "door 8 (EMC style)",
+    "Door 8 (EMC style)",
   },
   {
     "emc_gate_5_gray",
     "gate",
-    "gray door (EMC style, key 5)",
+    "Gray door (EMC style, key 5)",
   },
   {
     "emc_gate_6_gray",
     "gate",
-    "gray door (EMC style, key 6)",
+    "Gray door (EMC style, key 6)",
   },
   {
     "emc_gate_7_gray",
     "gate",
-    "gray door (EMC style, key 7)",
+    "Gray door (EMC style, key 7)",
   },
   {
     "emc_gate_8_gray",
     "gate",
-    "gray door (EMC style, key 8)",
+    "Gray door (EMC style, key 8)",
   },
   {
     "emc_key_5",
     "key",
-    "key 5 (EMC style)",
+    "Key 5 (EMC style)",
   },
   {
     "emc_key_6",
     "key",
-    "key 6 (EMC style)",
+    "Key 6 (EMC style)",
   },
   {
     "emc_key_7",
     "key",
-    "key 7 (EMC style)",
+    "Key 7 (EMC style)",
   },
   {
     "emc_key_8",
     "key",
-    "key 8 (EMC style)",
+    "Key 8 (EMC style)",
   },
   {
     "emc_android",
     "emc_android",
-    "android",
+    "Android",
   },
   {
     "emc_grass",
     "emc_grass",
-    "grass",
+    "Grass",
   },
   {
     "emc_magic_ball",
     "emc_magic_ball",
-    "magic ball",
+    "Magic ball",
   },
   {
     "emc_magic_ball.active",
     "emc_magic_ball",
-    "magic ball (activated)",
+    "Magic ball (activated)",
   },
   {
     "emc_magic_ball_switch",
     "emc_magic_ball_switch",
-    "magic ball switch (off)",
+    "Magic ball switch (off)",
   },
   {
     "emc_magic_ball_switch.active",
     "emc_magic_ball_switch",
-    "magic ball switch (on)",
+    "Magic ball switch (on)",
   },
   {
     "emc_spring_bumper",
     "emc_spring_bumper",
-    "spring bumper",
+    "Spring bumper",
   },
   {
     "emc_plant",
     "emc_plant",
-    "plant",
+    "Plant",
   },
   {
     "emc_lenses",
     "emc_lenses",
-    "lenses",
+    "Lenses",
   },
   {
     "emc_magnifier",
     "emc_magnifier",
-    "magnifier",
+    "Magnifier",
   },
   {
     "emc_wall_9",
     "wall",
-    "normal wall 9 (EMC style)"
+    "Normal wall 9 (EMC style)"
   },
   {
     "emc_wall_10",
     "wall",
-    "normal wall 10 (EMC style)"
+    "Normal wall 10 (EMC style)"
   },
   {
     "emc_wall_11",
     "wall",
-    "normal wall 11 (EMC style)"
+    "Normal wall 11 (EMC style)"
   },
   {
     "emc_wall_12",
     "wall",
-    "normal wall 12 (EMC style)"
+    "Normal wall 12 (EMC style)"
   },
   {
     "emc_wall_13",
     "wall",
-    "normal wall 13 (EMC style)"
+    "Normal wall 13 (EMC style)"
   },
   {
     "emc_wall_14",
     "wall",
-    "normal wall 14 (EMC style)"
+    "Normal wall 14 (EMC style)"
   },
   {
     "emc_wall_15",
     "wall",
-    "normal wall 15 (EMC style)"
+    "Normal wall 15 (EMC style)"
   },
   {
     "emc_wall_16",
     "wall",
-    "normal wall 16 (EMC style)"
+    "Normal wall 16 (EMC style)"
   },
   {
     "emc_wall_slippery_1",
     "wall",
-    "slippery wall 1 (EMC style)"
+    "Slippery wall 1 (EMC style)"
   },
   {
     "emc_wall_slippery_2",
     "wall",
-    "slippery wall 2 (EMC style)"
+    "Slippery wall 2 (EMC style)"
   },
   {
     "emc_wall_slippery_3",
     "wall",
-    "slippery wall 3 (EMC style)"
+    "Slippery wall 3 (EMC style)"
   },
   {
     "emc_wall_slippery_4",
     "wall",
-    "slippery wall 4 (EMC style)"
+    "Slippery wall 4 (EMC style)"
   },
   {
     "emc_fake_grass",
     "fake_grass",
-    "fake grass"
+    "Fake grass"
   },
   {
     "emc_fake_acid",
     "fake_acid",
-    "fake acid"
+    "Fake acid"
   },
   {
     "emc_dripper",
     "dripper",
-    "dripper"
+    "Dripper"
   },
   {
     "trigger_ce_value",
@@ -3740,27 +3745,27 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "yamyam.left",
     "yamyam",
-    "yam yam (starts moving left)"
+    "Yam yam (starts moving left)"
   },
   {
     "yamyam.right",
     "yamyam",
-    "yam yam (starts moving right)"
+    "Yam yam (starts moving right)"
   },
   {
     "yamyam.up",
     "yamyam",
-    "yam yam (starts moving up)"
+    "Yam yam (starts moving up)"
   },
   {
     "yamyam.down",
     "yamyam",
-    "yam yam (starts moving down)"
+    "Yam yam (starts moving down)"
   },
   {
     "bd_expandable_wall",
-    "wall",
-    "growing wall (horizontal, BD style)"
+    "bd_expandable_wall",
+    "Growing wall (horizontal, BD style)"
   },
   {
     "prev_ce_8",
@@ -3805,7 +3810,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "self",
     "self",
-    "the current custom element"
+    "The current custom element"
   },
   {
     "next_ce_1",
@@ -3850,772 +3855,772 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "any_element",
     "any_element",
-    "this element matches any element"
+    "This element matches any element"
   },
   {
     "steel_char_space",
     "steel_char",
-    "steel letter ' '"
+    "Steel letter ' '"
   },
   {
     "steel_char_exclam",
     "steel_char",
-    "steel letter '!'"
+    "Steel letter '!'"
   },
   {
     "steel_char_quotedbl",
     "steel_char",
-    "steel letter '\"'"
+    "Steel letter '\"'"
   },
   {
     "steel_char_numbersign",
     "steel_char",
-    "steel letter '#'"
+    "Steel letter '#'"
   },
   {
     "steel_char_dollar",
     "steel_char",
-    "steel letter '$'"
+    "Steel letter '$'"
   },
   {
     "steel_char_percent",
     "steel_char",
-    "steel letter '%'"
+    "Steel letter '%'"
   },
   {
     "steel_char_ampersand",
     "steel_char",
-    "steel letter '&'"
+    "Steel letter '&'"
   },
   {
     "steel_char_apostrophe",
     "steel_char",
-    "steel letter '''"
+    "Steel letter '''"
   },
   {
     "steel_char_parenleft",
     "steel_char",
-    "steel letter '('"
+    "Steel letter '('"
   },
   {
     "steel_char_parenright",
     "steel_char",
-    "steel letter ')'"
+    "Steel letter ')'"
   },
   {
     "steel_char_asterisk",
     "steel_char",
-    "steel letter '*'"
+    "Steel letter '*'"
   },
   {
     "steel_char_plus",
     "steel_char",
-    "steel letter '+'"
+    "Steel letter '+'"
   },
   {
     "steel_char_comma",
     "steel_char",
-    "steel letter ','"
+    "Steel letter ','"
   },
   {
     "steel_char_minus",
     "steel_char",
-    "steel letter '-'"
+    "Steel letter '-'"
   },
   {
     "steel_char_period",
     "steel_char",
-    "steel letter '.'"
+    "Steel letter '.'"
   },
   {
     "steel_char_slash",
     "steel_char",
-    "steel letter '/'"
+    "Steel letter '/'"
   },
   {
     "steel_char_0",
     "steel_char",
-    "steel letter '0'"
+    "Steel letter '0'"
   },
   {
     "steel_char_1",
     "steel_char",
-    "steel letter '1'"
+    "Steel letter '1'"
   },
   {
     "steel_char_2",
     "steel_char",
-    "steel letter '2'"
+    "Steel letter '2'"
   },
   {
     "steel_char_3",
     "steel_char",
-    "steel letter '3'"
+    "Steel letter '3'"
   },
   {
     "steel_char_4",
     "steel_char",
-    "steel letter '4'"
+    "Steel letter '4'"
   },
   {
     "steel_char_5",
     "steel_char",
-    "steel letter '5'"
+    "Steel letter '5'"
   },
   {
     "steel_char_6",
     "steel_char",
-    "steel letter '6'"
+    "Steel letter '6'"
   },
   {
     "steel_char_7",
     "steel_char",
-    "steel letter '7'"
+    "Steel letter '7'"
   },
   {
     "steel_char_8",
     "steel_char",
-    "steel letter '8'"
+    "Steel letter '8'"
   },
   {
     "steel_char_9",
     "steel_char",
-    "steel letter '9'"
+    "Steel letter '9'"
   },
   {
     "steel_char_colon",
     "steel_char",
-    "steel letter ':'"
+    "Steel letter ':'"
   },
   {
     "steel_char_semicolon",
     "steel_char",
-    "steel letter ';'"
+    "Steel letter ';'"
   },
   {
     "steel_char_less",
     "steel_char",
-    "steel letter '<'"
+    "Steel letter '<'"
   },
   {
     "steel_char_equal",
     "steel_char",
-    "steel letter '='"
+    "Steel letter '='"
   },
   {
     "steel_char_greater",
     "steel_char",
-    "steel letter '>'"
+    "Steel letter '>'"
   },
   {
     "steel_char_question",
     "steel_char",
-    "steel letter '?'"
+    "Steel letter '?'"
   },
   {
     "steel_char_at",
     "steel_char",
-    "steel letter '@'"
+    "Steel letter '@'"
   },
   {
     "steel_char_a",
     "steel_char",
-    "steel letter 'A'"
+    "Steel letter 'A'"
   },
   {
     "steel_char_b",
     "steel_char",
-    "steel letter 'B'"
+    "Steel letter 'B'"
   },
   {
     "steel_char_c",
     "steel_char",
-    "steel letter 'C'"
+    "Steel letter 'C'"
   },
   {
     "steel_char_d",
     "steel_char",
-    "steel letter 'D'"
+    "Steel letter 'D'"
   },
   {
     "steel_char_e",
     "steel_char",
-    "steel letter 'E'"
+    "Steel letter 'E'"
   },
   {
     "steel_char_f",
     "steel_char",
-    "steel letter 'F'"
+    "Steel letter 'F'"
   },
   {
     "steel_char_g",
     "steel_char",
-    "steel letter 'G'"
+    "Steel letter 'G'"
   },
   {
     "steel_char_h",
     "steel_char",
-    "steel letter 'H'"
+    "Steel letter 'H'"
   },
   {
     "steel_char_i",
     "steel_char",
-    "steel letter 'I'"
+    "Steel letter 'I'"
   },
   {
     "steel_char_j",
     "steel_char",
-    "steel letter 'J'"
+    "Steel letter 'J'"
   },
   {
     "steel_char_k",
     "steel_char",
-    "steel letter 'K'"
+    "Steel letter 'K'"
   },
   {
     "steel_char_l",
     "steel_char",
-    "steel letter 'L'"
+    "Steel letter 'L'"
   },
   {
     "steel_char_m",
     "steel_char",
-    "steel letter 'M'"
+    "Steel letter 'M'"
   },
   {
     "steel_char_n",
     "steel_char",
-    "steel letter 'N'"
+    "Steel letter 'N'"
   },
   {
     "steel_char_o",
     "steel_char",
-    "steel letter 'O'"
+    "Steel letter 'O'"
   },
   {
     "steel_char_p",
     "steel_char",
-    "steel letter 'P'"
+    "Steel letter 'P'"
   },
   {
     "steel_char_q",
     "steel_char",
-    "steel letter 'Q'"
+    "Steel letter 'Q'"
   },
   {
     "steel_char_r",
     "steel_char",
-    "steel letter 'R'"
+    "Steel letter 'R'"
   },
   {
     "steel_char_s",
     "steel_char",
-    "steel letter 'S'"
+    "Steel letter 'S'"
   },
   {
     "steel_char_t",
     "steel_char",
-    "steel letter 'T'"
+    "Steel letter 'T'"
   },
   {
     "steel_char_u",
     "steel_char",
-    "steel letter 'U'"
+    "Steel letter 'U'"
   },
   {
     "steel_char_v",
     "steel_char",
-    "steel letter 'V'"
+    "Steel letter 'V'"
   },
   {
     "steel_char_w",
     "steel_char",
-    "steel letter 'W'"
+    "Steel letter 'W'"
   },
   {
     "steel_char_x",
     "steel_char",
-    "steel letter 'X'"
+    "Steel letter 'X'"
   },
   {
     "steel_char_y",
     "steel_char",
-    "steel letter 'Y'"
+    "Steel letter 'Y'"
   },
   {
     "steel_char_z",
     "steel_char",
-    "steel letter 'Z'"
+    "Steel letter 'Z'"
   },
   {
     "steel_char_bracketleft",
     "steel_char",
-    "steel letter '['"
+    "Steel letter '['"
   },
   {
     "steel_char_backslash",
     "steel_char",
-    "steel letter '\\'"
+    "Steel letter '\\'"
   },
   {
     "steel_char_bracketright",
     "steel_char",
-    "steel letter ']'"
+    "Steel letter ']'"
   },
   {
     "steel_char_asciicircum",
     "steel_char",
-    "steel letter '^'"
+    "Steel letter '^'"
   },
   {
     "steel_char_underscore",
     "steel_char",
-    "steel letter '_'"
+    "Steel letter '_'"
   },
   {
     "steel_char_copyright",
     "steel_char",
-    "steel letter '\xa9'"
+    "Steel letter '\xa9'"
   },
   {
     "steel_char_aumlaut",
     "steel_char",
-    "steel letter '\xc4'"
+    "Steel letter '\xc4'"
   },
   {
     "steel_char_oumlaut",
     "steel_char",
-    "steel letter '\xd6'"
+    "Steel letter '\xd6'"
   },
   {
     "steel_char_uumlaut",
     "steel_char",
-    "steel letter '\xdc'"
+    "Steel letter '\xdc'"
   },
   {
     "steel_char_degree",
     "steel_char",
-    "steel letter '\xb0'"
+    "Steel letter '\xb0'"
   },
   {
     "steel_char_trademark",
     "steel_char",
-    "steel letter '\xae'"
+    "Steel letter '\xae'"
   },
   {
     "steel_char_cursor",
     "steel_char",
-    "steel letter '\xa0'"
+    "Steel letter '\xa0'"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_unused",
     "steel_char",
-    "steel letter ''"
+    "Steel letter ''"
   },
   {
     "steel_char_button",
     "steel_char",
-    "steel letter 'button'"
+    "Steel letter 'button'"
   },
   {
     "steel_char_up",
     "steel_char",
-    "steel letter 'up'"
+    "Steel letter 'up'"
   },
   {
     "steel_char_down",
     "steel_char",
-    "steel letter 'down'"
+    "Steel letter 'down'"
   },
   {
     "sperms",
     "frankie",
-    "sperms"
+    "Sperms"
   },
   {
     "bullet",
     "frankie",
-    "bullet"
+    "Bullet"
   },
   {
     "heart",
     "frankie",
-    "heart"
+    "Heart"
   },
   {
     "cross",
     "frankie",
-    "cross"
+    "Cross"
   },
   {
     "frankie",
     "frankie",
-    "frankie"
+    "Frankie"
   },
   {
     "sign_sperms",
     "sign",
-    "sign (sperms)"
+    "Sign (sperms)"
   },
   {
     "sign_bullet",
     "sign",
-    "sign (bullet)"
+    "Sign (bullet)"
   },
   {
     "sign_heart",
     "sign",
-    "sign (heart)"
+    "Sign (heart)"
   },
   {
     "sign_cross",
     "sign",
-    "sign (cross)"
+    "Sign (cross)"
   },
   {
     "sign_frankie",
     "sign",
-    "sign (frankie)"
+    "Sign (frankie)"
   },
   {
     "steel_exit_closed",
     "steel_exit",
-    "closed steel exit"
+    "Closed steel exit"
   },
   {
     "steel_exit_open",
     "steel_exit",
-    "open steel exit"
+    "Open steel exit"
   },
   {
     "dc_steelwall_1_left",
     "steelwall",
-    "steel wall 1 (left)"
+    "Steel wall 1 (left)"
   },
   {
     "dc_steelwall_1_right",
     "steelwall",
-    "steel wall 1 (right)"
+    "Steel wall 1 (right)"
   },
   {
     "dc_steelwall_1_top",
     "steelwall",
-    "steel wall 1 (top)"
+    "Steel wall 1 (top)"
   },
   {
     "dc_steelwall_1_bottom",
     "steelwall",
-    "steel wall 1 (bottom)"
+    "Steel wall 1 (bottom)"
   },
   {
     "dc_steelwall_1_horizontal",
     "steelwall",
-    "steel wall 1 (top/bottom)"
+    "Steel wall 1 (top/bottom)"
   },
   {
     "dc_steelwall_1_vertical",
     "steelwall",
-    "steel wall 1 (left/right)"
+    "Steel wall 1 (left/right)"
   },
   {
     "dc_steelwall_1_topleft",
     "steelwall",
-    "steel wall 1 (top/left)"
+    "Steel wall 1 (top/left)"
   },
   {
     "dc_steelwall_1_topright",
     "steelwall",
-    "steel wall 1 (top/right)"
+    "Steel wall 1 (top/right)"
   },
   {
     "dc_steelwall_1_bottomleft",
     "steelwall",
-    "steel wall 1 (bottom/left)"
+    "Steel wall 1 (bottom/left)"
   },
   {
     "dc_steelwall_1_bottomright",
     "steelwall",
-    "steel wall 1 (bottom/right)"
+    "Steel wall 1 (bottom/right)"
   },
   {
     "dc_steelwall_1_topleft_2",
     "steelwall",
-    "steel wall 1 (top/left corner)"
+    "Steel wall 1 (top/left corner)"
   },
   {
     "dc_steelwall_1_topright_2",
     "steelwall",
-    "steel wall 1 (top/right corner)"
+    "Steel wall 1 (top/right corner)"
   },
   {
     "dc_steelwall_1_bottomleft_2",
     "steelwall",
-    "steel wall 1 (bottom/left corner)"
+    "Steel wall 1 (bottom/left corner)"
   },
   {
     "dc_steelwall_1_bottomright_2",
     "steelwall",
-    "steel wall 1 (bottom/right corner)"
+    "Steel wall 1 (bottom/right corner)"
   },
   {
     "dc_steelwall_2_left",
     "steelwall",
-    "steel wall 2 (left)"
+    "Steel wall 2 (left)"
   },
   {
     "dc_steelwall_2_right",
     "steelwall",
-    "steel wall 2 (right)"
+    "Steel wall 2 (right)"
   },
   {
     "dc_steelwall_2_top",
     "steelwall",
-    "steel wall 2 (top)"
+    "Steel wall 2 (top)"
   },
   {
     "dc_steelwall_2_bottom",
     "steelwall",
-    "steel wall 2 (bottom)"
+    "Steel wall 2 (bottom)"
   },
   {
     "dc_steelwall_2_horizontal",
     "steelwall",
-    "steel wall 2 (horizontal)"
+    "Steel wall 2 (horizontal)"
   },
   {
     "dc_steelwall_2_vertical",
     "steelwall",
-    "steel wall 2 (vertical)"
+    "Steel wall 2 (vertical)"
   },
   {
     "dc_steelwall_2_middle",
     "steelwall",
-    "steel wall 2 (middle)"
+    "Steel wall 2 (middle)"
   },
   {
     "dc_steelwall_2_single",
     "steelwall",
-    "steel wall 2 (single)"
+    "Steel wall 2 (single)"
   },
   {
     "dc_switchgate_switch_up",
     "switchgate_switch",
-    "switch for switch gate (steel)"
+    "Switch for switch gate (steel)"
   },
   {
     "dc_switchgate_switch_down",
     "switchgate_switch",
-    "switch for switch gate (steel)"
+    "Switch for switch gate (steel)"
   },
   {
     "dc_timegate_switch",
     "timegate_switch",
-    "switch for time gate (steel)"
+    "Switch for time gate (steel)"
   },
   {
     "dc_timegate_switch.active",
     "timegate_switch",
-    "switch for time gate (steel)"
+    "Switch for time gate (steel)"
   },
   {
     "dc_landmine",
     "dc_landmine",
-    "land mine (DC style, removable)"
+    "Land mine (DC style, removable)"
   },
   {
     "expandable_steelwall",
     "steelwall",
-    "growing steel wall"
+    "Growing steel wall"
   },
   {
     "expandable_steelwall_horizontal",
     "steelwall",
-    "growing steel wall (horizontal)"
+    "Growing steel wall (horizontal)"
   },
   {
     "expandable_steelwall_vertical",
     "steelwall",
-    "growing steel wall (vertical)"
+    "Growing steel wall (vertical)"
   },
   {
     "expandable_steelwall_any",
     "steelwall",
-    "growing steel wall (any direction)"
+    "Growing steel wall (any direction)"
   },
   {
     "em_exit_closed",
     "em_exit",
-    "closed exit (EM style)"
+    "Closed exit (EM style)"
   },
   {
     "em_exit_open",
     "em_exit",
-    "open exit (EM style)"
+    "Open exit (EM style)"
   },
   {
     "em_steel_exit_closed",
     "em_steel_exit",
-    "closed steel exit (EM style)"
+    "Closed steel exit (EM style)"
   },
   {
     "em_steel_exit_open",
     "em_steel_exit",
-    "open steel exit (EM style)"
+    "Open steel exit (EM style)"
   },
   {
     "dc_gate_fake_gray",
     "gate",
-    "gray door (opened by no key)"
+    "Gray door (opened by no key)"
   },
   {
     "dc_magic_wall",
     "dc_magic_wall",
-    "magic wall (DC style)"
+    "Magic wall (DC style)"
   },
   {
     "quicksand_fast_empty",
     "quicksand",
-    "fast quicksand (empty)"
+    "Fast quicksand (empty)"
   },
   {
     "quicksand_fast_full",
     "quicksand",
-    "fast quicksand (with rock)"
+    "Fast quicksand (with rock)"
   },
   {
     "from_level_template",
     "from_level_template",
-    "element taken from level template"
+    "Element taken from level template"
   },
   {
     "mm_empty_space",
     "empty_space",
-    "empty space"
+    "Empty space"
   },
   {
     "mm_mirror_1",
     "mm_mirror",
-    "mirror (0\xb0)"
+    "Mirror (0\xb0)"
   },
   {
     "mm_mirror_2",
     "mm_mirror",
-    "mirror (11.25\xb0)"
+    "Mirror (11.25\xb0)"
   },
   {
     "mm_mirror_3",
     "mm_mirror",
-    "mirror (22.5\xb0)"
+    "Mirror (22.5\xb0)"
   },
   {
     "mm_mirror_4",
     "mm_mirror",
-    "mirror (33.75\xb0)"
+    "Mirror (33.75\xb0)"
   },
   {
     "mm_mirror_5",
     "mm_mirror",
-    "mirror (45\xb0)"
+    "Mirror (45\xb0)"
   },
   {
     "mm_mirror_6",
     "mm_mirror",
-    "mirror (56.25\xb0)"
+    "Mirror (56.25\xb0)"
   },
   {
     "mm_mirror_7",
     "mm_mirror",
-    "mirror (67.5\xb0)"
+    "Mirror (67.5\xb0)"
   },
   {
     "mm_mirror_8",
     "mm_mirror",
-    "mirror (78.75\xb0)"
+    "Mirror (78.75\xb0)"
   },
   {
     "mm_mirror_9",
     "mm_mirror",
-    "mirror (90\xb0)"
+    "Mirror (90\xb0)"
   },
   {
     "mm_mirror_10",
     "mm_mirror",
-    "mirror (101.25\xb0)"
+    "Mirror (101.25\xb0)"
   },
   {
     "mm_mirror_11",
     "mm_mirror",
-    "mirror (112.5\xb0)"
+    "Mirror (112.5\xb0)"
   },
   {
     "mm_mirror_12",
     "mm_mirror",
-    "mirror (123.75\xb0)"
+    "Mirror (123.75\xb0)"
   },
   {
     "mm_mirror_13",
     "mm_mirror",
-    "mirror (135\xb0)"
+    "Mirror (135\xb0)"
   },
   {
     "mm_mirror_14",
     "mm_mirror",
-    "mirror (146.25\xb0)"
+    "Mirror (146.25\xb0)"
   },
   {
     "mm_mirror_15",
     "mm_mirror",
-    "mirror (157.5\xb0)"
+    "Mirror (157.5\xb0)"
   },
   {
     "mm_mirror_16",
     "mm_mirror",
-    "mirror (168.75\xb0)"
+    "Mirror (168.75\xb0)"
   },
   {
     "mm_steel_grid_fixed_1",
     "mm_steel_grid_fixed",
-    "fixed steel polarizer (0\xb0)"
+    "Fixed steel polarizer (0\xb0)"
   },
   {
     "mm_steel_grid_fixed_2",
     "mm_steel_grid_fixed",
-    "fixed steel polarizer (90\xb0)"
+    "Fixed steel polarizer (90\xb0)"
   },
   {
     "mm_steel_grid_fixed_3",
     "mm_steel_grid_fixed",
-    "fixed steel polarizer (45\xb0)"
+    "Fixed steel polarizer (45\xb0)"
   },
   {
     "mm_steel_grid_fixed_4",
     "mm_steel_grid_fixed",
-    "fixed steel polarizer (135\xb0)"
+    "Fixed steel polarizer (135\xb0)"
   },
   {
     "mm_mcduffin.right",
@@ -4640,1577 +4645,1577 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "mm_exit_closed",
     "mm_exit",
-    "closed exit (MM style)"
+    "Closed exit (MM style)"
   },
   {
     "mm_exit_opening_1",
     "mm_exit",
-    "opening exit 1"
+    "Opening exit 1"
   },
   {
     "mm_exit_opening_2",
     "mm_exit",
-    "opening exit 2"
+    "Opening exit 2"
   },
   {
     "mm_exit_open",
     "mm_exit",
-    "open exit (MM style)"
+    "Open exit (MM style)"
   },
   {
     "mm_kettle",
     "mm_kettle",
-    "magic kettle"
+    "Magic cauldron"
   },
   {
     "mm_bomb",
     "mm_bomb",
-    "bomb (MM style)"
+    "Bomb (MM style)"
   },
   {
     "mm_prism",
     "mm_prism",
-    "prism"
+    "Prism"
   },
   {
     "mm_steel_wall_1",
     "mm_steel_wall",
-    "steel wall 1 (MM style)"
+    "Steel wall 1 (MM style)"
   },
   {
     "mm_steel_wall_2",
     "mm_steel_wall",
-    "steel wall 2 (MM style)"
+    "Steel wall 2 (MM style)"
   },
   {
     "mm_steel_wall_3",
     "mm_steel_wall",
-    "steel wall 3 (MM style)"
+    "Steel wall 3 (MM style)"
   },
   {
     "mm_steel_wall_4",
     "mm_steel_wall",
-    "steel wall 4 (MM style)"
+    "Steel wall 4 (MM style)"
   },
   {
     "mm_steel_wall_5",
     "mm_steel_wall",
-    "steel wall 5 (MM style)"
+    "Steel wall 5 (MM style)"
   },
   {
     "mm_steel_wall_6",
     "mm_steel_wall",
-    "steel wall 6 (MM style)"
+    "Steel wall 6 (MM style)"
   },
   {
     "mm_steel_wall_7",
     "mm_steel_wall",
-    "steel wall 7 (MM style)"
+    "Steel wall 7 (MM style)"
   },
   {
     "mm_steel_wall_8",
     "mm_steel_wall",
-    "steel wall 8 (MM style)"
+    "Steel wall 8 (MM style)"
   },
   {
     "mm_steel_wall_9",
     "mm_steel_wall",
-    "steel wall 9 (MM style)"
+    "Steel wall 9 (MM style)"
   },
   {
     "mm_steel_wall_10",
     "mm_steel_wall",
-    "steel wall 10 (MM style)"
+    "Steel wall 10 (MM style)"
   },
   {
     "mm_steel_wall_11",
     "mm_steel_wall",
-    "steel wall 11 (MM style)"
+    "Steel wall 11 (MM style)"
   },
   {
     "mm_steel_wall_12",
     "mm_steel_wall",
-    "steel wall 12 (MM style)"
+    "Steel wall 12 (MM style)"
   },
   {
     "mm_steel_wall_13",
     "mm_steel_wall",
-    "steel wall 13 (MM style)"
+    "Steel wall 13 (MM style)"
   },
   {
     "mm_steel_wall_14",
     "mm_steel_wall",
-    "steel wall 14 (MM style)"
+    "Steel wall 14 (MM style)"
   },
   {
     "mm_steel_wall_15",
     "mm_steel_wall",
-    "steel wall 15 (MM style)"
+    "Steel wall 15 (MM style)"
   },
   {
     "mm_steel_wall_16",
     "mm_steel_wall",
-    "steel wall 16 (MM style)"
+    "Steel wall 16 (MM style)"
   },
   {
     "mm_wooden_wall_1",
     "mm_wooden_wall",
-    "wooden wall 1 (MM style)"
+    "Wooden wall 1 (MM style)"
   },
   {
     "mm_wooden_wall_2",
     "mm_wooden_wall",
-    "wooden wall 2 (MM style)"
+    "Wooden wall 2 (MM style)"
   },
   {
     "mm_wooden_wall_3",
     "mm_wooden_wall",
-    "wooden wall 3 (MM style)"
+    "Wooden wall 3 (MM style)"
   },
   {
     "mm_wooden_wall_4",
     "mm_wooden_wall",
-    "wooden wall 4 (MM style)"
+    "Wooden wall 4 (MM style)"
   },
   {
     "mm_wooden_wall_5",
     "mm_wooden_wall",
-    "wooden wall 5 (MM style)"
+    "Wooden wall 5 (MM style)"
   },
   {
     "mm_wooden_wall_6",
     "mm_wooden_wall",
-    "wooden wall 6 (MM style)"
+    "Wooden wall 6 (MM style)"
   },
   {
     "mm_wooden_wall_7",
     "mm_wooden_wall",
-    "wooden wall 7 (MM style)"
+    "Wooden wall 7 (MM style)"
   },
   {
     "mm_wooden_wall_8",
     "mm_wooden_wall",
-    "wooden wall 8 (MM style)"
+    "Wooden wall 8 (MM style)"
   },
   {
     "mm_wooden_wall_9",
     "mm_wooden_wall",
-    "wooden wall 9 (MM style)"
+    "Wooden wall 9 (MM style)"
   },
   {
     "mm_wooden_wall_10",
     "mm_wooden_wall",
-    "wooden wall 10 (MM style)"
+    "Wooden wall 10 (MM style)"
   },
   {
     "mm_wooden_wall_11",
     "mm_wooden_wall",
-    "wooden wall 11 (MM style)"
+    "Wooden wall 11 (MM style)"
   },
   {
     "mm_wooden_wall_12",
     "mm_wooden_wall",
-    "wooden wall 12 (MM style)"
+    "Wooden wall 12 (MM style)"
   },
   {
     "mm_wooden_wall_13",
     "mm_wooden_wall",
-    "wooden wall 13 (MM style)"
+    "Wooden wall 13 (MM style)"
   },
   {
     "mm_wooden_wall_14",
     "mm_wooden_wall",
-    "wooden wall 14 (MM style)"
+    "Wooden wall 14 (MM style)"
   },
   {
     "mm_wooden_wall_15",
     "mm_wooden_wall",
-    "wooden wall 15 (MM style)"
+    "Wooden wall 15 (MM style)"
   },
   {
     "mm_wooden_wall_16",
     "mm_wooden_wall",
-    "wooden wall 16 (MM style)"
+    "Wooden wall 16 (MM style)"
   },
   {
     "mm_ice_wall_1",
     "mm_ice_wall",
-    "ice wall 1"
+    "Ice wall 1"
   },
   {
     "mm_ice_wall_2",
     "mm_ice_wall",
-    "ice wall 2"
+    "Ice wall 2"
   },
   {
     "mm_ice_wall_3",
     "mm_ice_wall",
-    "ice wall 3"
+    "Ice wall 3"
   },
   {
     "mm_ice_wall_4",
     "mm_ice_wall",
-    "ice wall 4"
+    "Ice wall 4"
   },
   {
     "mm_ice_wall_5",
     "mm_ice_wall",
-    "ice wall 5"
+    "Ice wall 5"
   },
   {
     "mm_ice_wall_6",
     "mm_ice_wall",
-    "ice wall 6"
+    "Ice wall 6"
   },
   {
     "mm_ice_wall_7",
     "mm_ice_wall",
-    "ice wall 7"
+    "Ice wall 7"
   },
   {
     "mm_ice_wall_8",
     "mm_ice_wall",
-    "ice wall 8"
+    "Ice wall 8"
   },
   {
     "mm_ice_wall_9",
     "mm_ice_wall",
-    "ice wall 9"
+    "Ice wall 9"
   },
   {
     "mm_ice_wall_10",
     "mm_ice_wall",
-    "ice wall 10"
+    "Ice wall 10"
   },
   {
     "mm_ice_wall_11",
     "mm_ice_wall",
-    "ice wall 11"
+    "Ice wall 11"
   },
   {
     "mm_ice_wall_12",
     "mm_ice_wall",
-    "ice wall 12"
+    "Ice wall 12"
   },
   {
     "mm_ice_wall_13",
     "mm_ice_wall",
-    "ice wall 13"
+    "Ice wall 13"
   },
   {
     "mm_ice_wall_14",
     "mm_ice_wall",
-    "ice wall 14"
+    "Ice wall 14"
   },
   {
     "mm_ice_wall_15",
     "mm_ice_wall",
-    "ice wall 15"
+    "Ice wall 15"
   },
   {
     "mm_ice_wall_16",
     "mm_ice_wall",
-    "ice wall 16"
+    "Ice wall 16"
   },
   {
     "mm_amoeba_wall_1",
     "mm_amoeba_wall",
-    "amoeba wall 1"
+    "Amoeba wall 1"
   },
   {
     "mm_amoeba_wall_2",
     "mm_amoeba_wall",
-    "amoeba wall 2"
+    "Amoeba wall 2"
   },
   {
     "mm_amoeba_wall_3",
     "mm_amoeba_wall",
-    "amoeba wall 3"
+    "Amoeba wall 3"
   },
   {
     "mm_amoeba_wall_4",
     "mm_amoeba_wall",
-    "amoeba wall 4"
+    "Amoeba wall 4"
   },
   {
     "mm_amoeba_wall_5",
     "mm_amoeba_wall",
-    "amoeba wall 5"
+    "Amoeba wall 5"
   },
   {
     "mm_amoeba_wall_6",
     "mm_amoeba_wall",
-    "amoeba wall 6"
+    "Amoeba wall 6"
   },
   {
     "mm_amoeba_wall_7",
     "mm_amoeba_wall",
-    "amoeba wall 7"
+    "Amoeba wall 7"
   },
   {
     "mm_amoeba_wall_8",
     "mm_amoeba_wall",
-    "amoeba wall 8"
+    "Amoeba wall 8"
   },
   {
     "mm_amoeba_wall_9",
     "mm_amoeba_wall",
-    "amoeba wall 9"
+    "Amoeba wall 9"
   },
   {
     "mm_amoeba_wall_10",
     "mm_amoeba_wall",
-    "amoeba wall 10"
+    "Amoeba wall 10"
   },
   {
     "mm_amoeba_wall_11",
     "mm_amoeba_wall",
-    "amoeba wall 11"
+    "Amoeba wall 11"
   },
   {
     "mm_amoeba_wall_12",
     "mm_amoeba_wall",
-    "amoeba wall 12"
+    "Amoeba wall 12"
   },
   {
     "mm_amoeba_wall_13",
     "mm_amoeba_wall",
-    "amoeba wall 13"
+    "Amoeba wall 13"
   },
   {
     "mm_amoeba_wall_14",
     "mm_amoeba_wall",
-    "amoeba wall 14"
+    "Amoeba wall 14"
   },
   {
     "mm_amoeba_wall_15",
     "mm_amoeba_wall",
-    "amoeba wall 15"
+    "Amoeba wall 15"
   },
   {
     "mm_amoeba_wall_16",
     "mm_amoeba_wall",
-    "amoeba wall 16"
+    "Amoeba wall 16"
   },
   {
     "mm_wooden_block",
     "mm_wooden_block",
-    "wooden block"
+    "Wooden block"
   },
   {
     "mm_gray_ball",
     "mm_gray_ball",
-    "gray ball"
+    "Gray ball"
   },
   {
     "mm_teleporter_1",
     "mm_teleporter",
-    "teleporter (0\xb0)"
+    "Teleporter (0\xb0)"
   },
   {
     "mm_teleporter_2",
     "mm_teleporter",
-    "teleporter (22.5\xb0)"
+    "Teleporter (22.5\xb0)"
   },
   {
     "mm_teleporter_3",
     "mm_teleporter",
-    "teleporter (45\xb0)"
+    "Teleporter (45\xb0)"
   },
   {
     "mm_teleporter_4",
     "mm_teleporter",
-    "teleporter (67.5\xb0)"
+    "Teleporter (67.5\xb0)"
   },
   {
     "mm_teleporter_5",
     "mm_teleporter",
-    "teleporter (90\xb0)"
+    "Teleporter (90\xb0)"
   },
   {
     "mm_teleporter_6",
     "mm_teleporter",
-    "teleporter (112.5\xb0)"
+    "Teleporter (112.5\xb0)"
   },
   {
     "mm_teleporter_7",
     "mm_teleporter",
-    "teleporter (135\xb0)"
+    "Teleporter (135\xb0)"
   },
   {
     "mm_teleporter_8",
     "mm_teleporter",
-    "teleporter (157.5\xb0)"
+    "Teleporter (157.5\xb0)"
   },
   {
     "mm_teleporter_9",
     "mm_teleporter",
-    "teleporter (180\xb0)"
+    "Teleporter (180\xb0)"
   },
   {
     "mm_teleporter_10",
     "mm_teleporter",
-    "teleporter (202.5\xb0)"
+    "Teleporter (202.5\xb0)"
   },
   {
     "mm_teleporter_11",
     "mm_teleporter",
-    "teleporter (225\xb0)"
+    "Teleporter (225\xb0)"
   },
   {
     "mm_teleporter_12",
     "mm_teleporter",
-    "teleporter (247.5\xb0)"
+    "Teleporter (247.5\xb0)"
   },
   {
     "mm_teleporter_13",
     "mm_teleporter",
-    "teleporter (270\xb0)"
+    "Teleporter (270\xb0)"
   },
   {
     "mm_teleporter_14",
     "mm_teleporter",
-    "teleporter (292.5\xb0)"
+    "Teleporter (292.5\xb0)"
   },
   {
     "mm_teleporter_15",
     "mm_teleporter",
-    "teleporter (315\xb0)"
+    "Teleporter (315\xb0)"
   },
   {
     "mm_teleporter_16",
     "mm_teleporter",
-    "teleporter (337.5\xb0)"
+    "Teleporter (337.5\xb0)"
   },
   {
     "mm_fuse.active",
     "mm_fuse",
-    "fuse (on)"
+    "Fuse (on)"
   },
   {
     "mm_pacman.right",
     "mm_pacman",
-    "pac man (starts moving right)"
+    "Pac man (starts moving right)"
   },
   {
     "mm_pacman.up",
     "mm_pacman",
-    "pac man (starts moving up)"
+    "Pac man (starts moving up)"
   },
   {
     "mm_pacman.left",
     "mm_pacman",
-    "pac man (starts moving left)"
+    "Pac man (starts moving left)"
   },
   {
     "mm_pacman.down",
     "mm_pacman",
-    "pac man (starts moving down)"
+    "Pac man (starts moving down)"
   },
   {
     "mm_polarizer_1",
     "mm_polarizer",
-    "polarizer (0\xb0)"
+    "Polarizer (0\xb0)"
   },
   {
     "mm_polarizer_2",
     "mm_polarizer",
-    "polarizer (11.25\xb0)"
+    "Polarizer (11.25\xb0)"
   },
   {
     "mm_polarizer_3",
     "mm_polarizer",
-    "polarizer (22.5\xb0)"
+    "Polarizer (22.5\xb0)"
   },
   {
     "mm_polarizer_4",
     "mm_polarizer",
-    "polarizer (33.75\xb0)"
+    "Polarizer (33.75\xb0)"
   },
   {
     "mm_polarizer_5",
     "mm_polarizer",
-    "polarizer (45\xb0)"
+    "Polarizer (45\xb0)"
   },
   {
     "mm_polarizer_6",
     "mm_polarizer",
-    "polarizer (56.25\xb0)"
+    "Polarizer (56.25\xb0)"
   },
   {
     "mm_polarizer_7",
     "mm_polarizer",
-    "polarizer (67.5\xb0)"
+    "Polarizer (67.5\xb0)"
   },
   {
     "mm_polarizer_8",
     "mm_polarizer",
-    "polarizer (78.75\xb0)"
+    "Polarizer (78.75\xb0)"
   },
   {
     "mm_polarizer_9",
     "mm_polarizer",
-    "polarizer (90\xb0)"
+    "Polarizer (90\xb0)"
   },
   {
     "mm_polarizer_10",
     "mm_polarizer",
-    "polarizer (101.25\xb0)"
+    "Polarizer (101.25\xb0)"
   },
   {
     "mm_polarizer_11",
     "mm_polarizer",
-    "polarizer (112.5\xb0)"
+    "Polarizer (112.5\xb0)"
   },
   {
     "mm_polarizer_12",
     "mm_polarizer",
-    "polarizer (123.75\xb0)"
+    "Polarizer (123.75\xb0)"
   },
   {
     "mm_polarizer_13",
     "mm_polarizer",
-    "polarizer (135\xb0)"
+    "Polarizer (135\xb0)"
   },
   {
     "mm_polarizer_14",
     "mm_polarizer",
-    "polarizer (146.25\xb0)"
+    "Polarizer (146.25\xb0)"
   },
   {
     "mm_polarizer_15",
     "mm_polarizer",
-    "polarizer (157.5\xb0)"
+    "Polarizer (157.5\xb0)"
   },
   {
     "mm_polarizer_16",
     "mm_polarizer",
-    "polarizer (168.75\xb0)"
+    "Polarizer (168.75\xb0)"
   },
   {
     "mm_polarizer_cross_1",
     "mm_polarizer_cross",
-    "two-way polarizer (0\xb0)"
+    "Two-way polarizer (0\xb0)"
   },
   {
     "mm_polarizer_cross_2",
     "mm_polarizer_cross",
-    "two-way polarizer (22.5\xb0)"
+    "Two-way polarizer (22.5\xb0)"
   },
   {
     "mm_polarizer_cross_3",
     "mm_polarizer_cross",
-    "two-way polarizer (45\xb0)"
+    "Two-way polarizer (45\xb0)"
   },
   {
     "mm_polarizer_cross_4",
     "mm_polarizer_cross",
-    "two-way polarizer (67.5\xb0)"
+    "Two-way polarizer (67.5\xb0)"
   },
   {
     "mm_mirror_fixed_1",
     "mm_mirror_fixed",
-    "fixed mirror (0\xb0)"
+    "Fixed mirror (0\xb0)"
   },
   {
     "mm_mirror_fixed_2",
     "mm_mirror_fixed",
-    "fixed mirror (0\xb0)"
+    "Fixed mirror (45\xb0)"
   },
   {
     "mm_mirror_fixed_3",
     "mm_mirror_fixed",
-    "fixed mirror (0\xb0)"
+    "Fixed mirror (90\xb0)"
   },
   {
     "mm_mirror_fixed_4",
     "mm_mirror_fixed",
-    "fixed mirror (0\xb0)"
+    "Fixed mirror (135\xb0)"
   },
   {
     "mm_steel_lock",
     "mm_steel_lock",
-    "steel lock"
+    "Steel lock"
   },
   {
     "mm_key",
     "mm_key",
-    "key (MM style)"
+    "Key (MM style)"
   },
   {
     "mm_lightbulb",
     "mm_lightbulb",
-    "light bulb (off)"
+    "Light bulb (off)"
   },
   {
     "mm_lightbulb.active",
     "mm_lightbulb",
-    "light bulb (on)"
+    "Light bulb (on)"
   },
   {
     "mm_lightball",
     "mm_lightball",
-    "bonus ball"
+    "Bonus ball"
   },
   {
     "mm_steel_block",
     "mm_steel_block",
-    "steel block"
+    "Steel block"
   },
   {
     "mm_wooden_lock",
     "mm_wooden_lock",
-    "wooden lock"
+    "Wooden lock"
   },
   {
     "mm_fuel_full",
     "mm_fuel",
-    "extra energy ball (full)"
+    "Extra energy ball (full)"
   },
   {
     "mm_wooden_grid_fixed_1",
     "mm_wooden_grid_fixed",
-    "fixed wooden polarizer (0\xb0)"
+    "Fixed wooden polarizer (0\xb0)"
   },
   {
     "mm_wooden_grid_fixed_2",
     "mm_wooden_grid_fixed",
-    "fixed wooden polarizer (90\xb0)"
+    "Fixed wooden polarizer (90\xb0)"
   },
   {
     "mm_wooden_grid_fixed_3",
     "mm_wooden_grid_fixed",
-    "fixed wooden polarizer (45\xb0)"
+    "Fixed wooden polarizer (45\xb0)"
   },
   {
     "mm_wooden_grid_fixed_4",
     "mm_wooden_grid_fixed",
-    "fixed wooden polarizer (135\xb0)"
+    "Fixed wooden polarizer (135\xb0)"
   },
   {
     "mm_fuel_empty",
     "mm_fuel",
-    "extra energy ball (empty)"
+    "Extra energy ball (empty)"
   },
   {
-    "mm_unused_156",
-    "unused",
-    "(not used)"
+    "mm_envelope_1",
+    "mm_envelope",
+    "Mail envelope 1 (MM style)"
   },
   {
-    "mm_unused_157",
-    "unused",
-    "(not used)"
+    "mm_envelope_2",
+    "mm_envelope",
+    "Mail envelope 2 (MM style)"
   },
   {
-    "mm_unused_158",
-    "unused",
-    "(not used)"
+    "mm_envelope_3",
+    "mm_envelope",
+    "Mail envelope 3 (MM style)"
   },
   {
-    "mm_unused_159",
-    "unused",
-    "(not used)"
+    "mm_envelope_4",
+    "mm_envelope",
+    "Mail envelope 4 (MM style)"
   },
   {
     "df_mirror_1",
     "df_mirror",
-    "mirror (DF style) (0\xb0)"
+    "Mirror (DF style) (0\xb0)"
   },
   {
     "df_mirror_2",
     "df_mirror",
-    "mirror (DF style) (11.25\xb0)"
+    "Mirror (DF style) (11.25\xb0)"
   },
   {
     "df_mirror_3",
     "df_mirror",
-    "mirror (DF style) (22.5\xb0)"
+    "Mirror (DF style) (22.5\xb0)"
   },
   {
     "df_mirror_4",
     "df_mirror",
-    "mirror (DF style) (33.75\xb0)"
+    "Mirror (DF style) (33.75\xb0)"
   },
   {
     "df_mirror_5",
     "df_mirror",
-    "mirror (DF style) (45\xb0)"
+    "Mirror (DF style) (45\xb0)"
   },
   {
     "df_mirror_6",
     "df_mirror",
-    "mirror (DF style) (56.25\xb0)"
+    "Mirror (DF style) (56.25\xb0)"
   },
   {
     "df_mirror_7",
     "df_mirror",
-    "mirror (DF style) (67.5\xb0)"
+    "Mirror (DF style) (67.5\xb0)"
   },
   {
     "df_mirror_8",
     "df_mirror",
-    "mirror (DF style) (78.75\xb0)"
+    "Mirror (DF style) (78.75\xb0)"
   },
   {
     "df_mirror_9",
     "df_mirror",
-    "mirror (DF style) (90\xb0)"
+    "Mirror (DF style) (90\xb0)"
   },
   {
     "df_mirror_10",
     "df_mirror",
-    "mirror (DF style) (101.25\xb0)"
+    "Mirror (DF style) (101.25\xb0)"
   },
   {
     "df_mirror_11",
     "df_mirror",
-    "mirror (DF style) (112.5\xb0)"
+    "Mirror (DF style) (112.5\xb0)"
   },
   {
     "df_mirror_12",
     "df_mirror",
-    "mirror (DF style) (123.75\xb0)"
+    "Mirror (DF style) (123.75\xb0)"
   },
   {
     "df_mirror_13",
     "df_mirror",
-    "mirror (DF style) (135\xb0)"
+    "Mirror (DF style) (135\xb0)"
   },
   {
     "df_mirror_14",
     "df_mirror",
-    "mirror (DF style) (146.25\xb0)"
+    "Mirror (DF style) (146.25\xb0)"
   },
   {
     "df_mirror_15",
     "df_mirror",
-    "mirror (DF style) (157.5\xb0)"
+    "Mirror (DF style) (157.5\xb0)"
   },
   {
     "df_mirror_16",
     "df_mirror",
-    "mirror (DF style) (168.75\xb0)"
+    "Mirror (DF style) (168.75\xb0)"
   },
   {
     "df_wooden_grid_fixed_1",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (0\xb0)"
+    "Fixed wooden polarizer (DF) (0\xb0)"
   },
   {
     "df_wooden_grid_fixed_2",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (22.5\xb0)"
+    "Fixed wooden polarizer (DF) (22.5\xb0)"
   },
   {
     "df_wooden_grid_fixed_3",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (45\xb0)"
+    "Fixed wooden polarizer (DF) (45\xb0)"
   },
   {
     "df_wooden_grid_fixed_4",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (67.5\xb0)"
+    "Fixed wooden polarizer (DF) (67.5\xb0)"
   },
   {
     "df_wooden_grid_fixed_5",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (90\xb0)"
+    "Fixed wooden polarizer (DF) (90\xb0)"
   },
   {
     "df_wooden_grid_fixed_6",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (112.5\xb0)"
+    "Fixed wooden polarizer (DF) (112.5\xb0)"
   },
   {
     "df_wooden_grid_fixed_7",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (135\xb0)"
+    "Fixed wooden polarizer (DF) (135\xb0)"
   },
   {
     "df_wooden_grid_fixed_8",
     "df_wooden_grid_fixed",
-    "fixed wooden polarizer (157.5\xb0)"
+    "Fixed wooden polarizer (DF) (157.5\xb0)"
   },
   {
     "df_steel_grid_fixed_1",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (0\xb0)"
+    "Fixed steel polarizer (DF) (0\xb0)"
   },
   {
     "df_steel_grid_fixed_2",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (22.5\xb0)"
+    "Fixed steel polarizer (DF) (22.5\xb0)"
   },
   {
     "df_steel_grid_fixed_3",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (45\xb0)"
+    "Fixed steel polarizer (DF) (45\xb0)"
   },
   {
     "df_steel_grid_fixed_4",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (67.5\xb0)"
+    "Fixed steel polarizer (DF) (67.5\xb0)"
   },
   {
     "df_steel_grid_fixed_5",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (90\xb0)"
+    "Fixed steel polarizer (DF) (90\xb0)"
   },
   {
     "df_steel_grid_fixed_6",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (112.5\xb0)"
+    "Fixed steel polarizer (DF) (112.5\xb0)"
   },
   {
     "df_steel_grid_fixed_7",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (135\xb0)"
+    "Fixed steel polarizer (DF) (135\xb0)"
   },
   {
     "df_steel_grid_fixed_8",
     "df_steel_grid_fixed",
-    "fixed steel polarizer (157.5\xb0)"
+    "Fixed steel polarizer (DF) (157.5\xb0)"
   },
   {
     "df_wooden_wall_1",
     "df_wooden_wall",
-    "wooden wall 1 (DF style)"
+    "Wooden wall 1 (DF style)"
   },
   {
     "df_wooden_wall_2",
     "df_wooden_wall",
-    "wooden wall 2 (DF style)"
+    "Wooden wall 2 (DF style)"
   },
   {
     "df_wooden_wall_3",
     "df_wooden_wall",
-    "wooden wall 3 (DF style)"
+    "Wooden wall 3 (DF style)"
   },
   {
     "df_wooden_wall_4",
     "df_wooden_wall",
-    "wooden wall 4 (DF style)"
+    "Wooden wall 4 (DF style)"
   },
   {
     "df_wooden_wall_5",
     "df_wooden_wall",
-    "wooden wall 5 (DF style)"
+    "Wooden wall 5 (DF style)"
   },
   {
     "df_wooden_wall_6",
     "df_wooden_wall",
-    "wooden wall 6 (DF style)"
+    "Wooden wall 6 (DF style)"
   },
   {
     "df_wooden_wall_7",
     "df_wooden_wall",
-    "wooden wall 7 (DF style)"
+    "Wooden wall 7 (DF style)"
   },
   {
     "df_wooden_wall_8",
     "df_wooden_wall",
-    "wooden wall 8 (DF style)"
+    "Wooden wall 8 (DF style)"
   },
   {
     "df_wooden_wall_9",
     "df_wooden_wall",
-    "wooden wall 9 (DF style)"
+    "Wooden wall 9 (DF style)"
   },
   {
     "df_wooden_wall_10",
     "df_wooden_wall",
-    "wooden wall 10 (DF style)"
+    "Wooden wall 10 (DF style)"
   },
   {
     "df_wooden_wall_11",
     "df_wooden_wall",
-    "wooden wall 11 (DF style)"
+    "Wooden wall 11 (DF style)"
   },
   {
     "df_wooden_wall_12",
     "df_wooden_wall",
-    "wooden wall 12 (DF style)"
+    "Wooden wall 12 (DF style)"
   },
   {
     "df_wooden_wall_13",
     "df_wooden_wall",
-    "wooden wall 13 (DF style)"
+    "Wooden wall 13 (DF style)"
   },
   {
     "df_wooden_wall_14",
     "df_wooden_wall",
-    "wooden wall 14 (DF style)"
+    "Wooden wall 14 (DF style)"
   },
   {
     "df_wooden_wall_15",
     "df_wooden_wall",
-    "wooden wall 15 (DF style)"
+    "Wooden wall 15 (DF style)"
   },
   {
     "df_wooden_wall_16",
     "df_wooden_wall",
-    "wooden wall 16 (DF style)"
+    "Wooden wall 16 (DF style)"
   },
   {
     "df_steel_wall_1",
     "df_steel_wall",
-    "steel wall 1 (DF style)"
+    "Steel wall 1 (DF style)"
   },
   {
     "df_steel_wall_2",
     "df_steel_wall",
-    "steel wall 2 (DF style)"
+    "Steel wall 2 (DF style)"
   },
   {
     "df_steel_wall_3",
     "df_steel_wall",
-    "steel wall 3 (DF style)"
+    "Steel wall 3 (DF style)"
   },
   {
     "df_steel_wall_4",
     "df_steel_wall",
-    "steel wall 4 (DF style)"
+    "Steel wall 4 (DF style)"
   },
   {
     "df_steel_wall_5",
     "df_steel_wall",
-    "steel wall 5 (DF style)"
+    "Steel wall 5 (DF style)"
   },
   {
     "df_steel_wall_6",
     "df_steel_wall",
-    "steel wall 6 (DF style)"
+    "Steel wall 6 (DF style)"
   },
   {
     "df_steel_wall_7",
     "df_steel_wall",
-    "steel wall 7 (DF style)"
+    "Steel wall 7 (DF style)"
   },
   {
     "df_steel_wall_8",
     "df_steel_wall",
-    "steel wall 8 (DF style)"
+    "Steel wall 8 (DF style)"
   },
   {
     "df_steel_wall_9",
     "df_steel_wall",
-    "steel wall 9 (DF style)"
+    "Steel wall 9 (DF style)"
   },
   {
     "df_steel_wall_10",
     "df_steel_wall",
-    "steel wall 10 (DF style)"
+    "Steel wall 10 (DF style)"
   },
   {
     "df_steel_wall_11",
     "df_steel_wall",
-    "steel wall 11 (DF style)"
+    "Steel wall 11 (DF style)"
   },
   {
     "df_steel_wall_12",
     "df_steel_wall",
-    "steel wall 12 (DF style)"
+    "Steel wall 12 (DF style)"
   },
   {
     "df_steel_wall_13",
     "df_steel_wall",
-    "steel wall 13 (DF style)"
+    "Steel wall 13 (DF style)"
   },
   {
     "df_steel_wall_14",
     "df_steel_wall",
-    "steel wall 14 (DF style)"
+    "Steel wall 14 (DF style)"
   },
   {
     "df_steel_wall_15",
     "df_steel_wall",
-    "steel wall 15 (DF style)"
+    "Steel wall 15 (DF style)"
   },
   {
     "df_steel_wall_16",
     "df_steel_wall",
-    "steel wall 16 (DF style)"
+    "Steel wall 16 (DF style)"
   },
   {
     "df_empty_space",
     "empty_space",
-    "empty space"
+    "Empty space"
   },
   {
     "df_cell",
     "df_cell",
-    "cell"
+    "Cell"
   },
   {
     "df_mine",
     "df_mine",
-    "mine"
+    "Mine"
   },
   {
     "df_refractor",
     "df_refractor",
-    "refractor"
+    "Refractor"
   },
   {
     "df_laser.right",
     "df_laser",
-    "laser cannon (shooting right)"
+    "Laser cannon (shooting right)"
   },
   {
     "df_laser.up",
     "df_laser",
-    "laser cannon (shooting up)"
+    "Laser cannon (shooting up)"
   },
   {
     "df_laser.left",
     "df_laser",
-    "laser cannon (shooting left)"
+    "Laser cannon (shooting left)"
   },
   {
     "df_laser.down",
     "df_laser",
-    "laser cannon (shooting down)"
+    "Laser cannon (shooting down)"
   },
   {
     "df_receiver.right",
     "df_receiver",
-    "laser receiver (directed right)"
+    "Laser receiver (directed right)"
   },
   {
     "df_receiver.up",
     "df_receiver",
-    "laser receiver (directed up)"
+    "Laser receiver (directed up)"
   },
   {
     "df_receiver.left",
     "df_receiver",
-    "laser receiver (directed left)"
+    "Laser receiver (directed left)"
   },
   {
     "df_receiver.down",
     "df_receiver",
-    "laser receiver (directed down)"
+    "Laser receiver (directed down)"
   },
   {
     "df_fibre_optic_red_1",
     "df_fibre_optic",
-    "red fibre optic (part 1)"
+    "Red fibre optic (part 1)"
   },
   {
     "df_fibre_optic_red_2",
     "df_fibre_optic",
-    "red fibre optic (part 2)"
+    "Red fibre optic (part 2)"
   },
   {
     "df_fibre_optic_yellow_1",
     "df_fibre_optic",
-    "yellow fibre optic (part 1)"
+    "Yellow fibre optic (part 1)"
   },
   {
     "df_fibre_optic_yellow_2",
     "df_fibre_optic",
-    "yellow fibre optic (part 2)"
+    "Yellow fibre optic (part 2)"
   },
   {
     "df_fibre_optic_green_1",
     "df_fibre_optic",
-    "green fibre optic (part 1)"
+    "Green fibre optic (part 1)"
   },
   {
     "df_fibre_optic_green_2",
     "df_fibre_optic",
-    "green fibre optic (part 2)"
+    "Green fibre optic (part 2)"
   },
   {
     "df_fibre_optic_blue_1",
     "df_fibre_optic",
-    "blue fibre optic (part 1)"
+    "Blue fibre optic (part 1)"
   },
   {
     "df_fibre_optic_blue_2",
     "df_fibre_optic",
-    "blue fibre optic (part 2)"
+    "Blue fibre optic (part 2)"
   },
   {
     "df_mirror_rotating_1",
     "df_mirror_rotating",
-    "rotating mirror (0\xb0)"
+    "Rotating mirror (0\xb0)"
   },
   {
     "df_mirror_rotating_2",
     "df_mirror_rotating",
-    "rotating mirror (11.25\xb0)"
+    "Rotating mirror (11.25\xb0)"
   },
   {
     "df_mirror_rotating_3",
     "df_mirror_rotating",
-    "rotating mirror (22.5\xb0)"
+    "Rotating mirror (22.5\xb0)"
   },
   {
     "df_mirror_rotating_4",
     "df_mirror_rotating",
-    "rotating mirror (33.75\xb0)"
+    "Rotating mirror (33.75\xb0)"
   },
   {
     "df_mirror_rotating_5",
     "df_mirror_rotating",
-    "rotating mirror (45\xb0)"
+    "Rotating mirror (45\xb0)"
   },
   {
     "df_mirror_rotating_6",
     "df_mirror_rotating",
-    "rotating mirror (56.25\xb0)"
+    "Rotating mirror (56.25\xb0)"
   },
   {
     "df_mirror_rotating_7",
     "df_mirror_rotating",
-    "rotating mirror (67.5\xb0)"
+    "Rotating mirror (67.5\xb0)"
   },
   {
     "df_mirror_rotating_8",
     "df_mirror_rotating",
-    "rotating mirror (78.75\xb0)"
+    "Rotating mirror (78.75\xb0)"
   },
   {
     "df_mirror_rotating_9",
     "df_mirror_rotating",
-    "rotating mirror (90\xb0)"
+    "Rotating mirror (90\xb0)"
   },
   {
     "df_mirror_rotating_10",
     "df_mirror_rotating",
-    "rotating mirror (101.25\xb0)"
+    "Rotating mirror (101.25\xb0)"
   },
   {
     "df_mirror_rotating_11",
     "df_mirror_rotating",
-    "rotating mirror (112.5\xb0)"
+    "Rotating mirror (112.5\xb0)"
   },
   {
     "df_mirror_rotating_12",
     "df_mirror_rotating",
-    "rotating mirror (123.75\xb0)"
+    "Rotating mirror (123.75\xb0)"
   },
   {
     "df_mirror_rotating_13",
     "df_mirror_rotating",
-    "rotating mirror (135\xb0)"
+    "Rotating mirror (135\xb0)"
   },
   {
     "df_mirror_rotating_14",
     "df_mirror_rotating",
-    "rotating mirror (146.25\xb0)"
+    "Rotating mirror (146.25\xb0)"
   },
   {
     "df_mirror_rotating_15",
     "df_mirror_rotating",
-    "rotating mirror (157.5\xb0)"
+    "Rotating mirror (157.5\xb0)"
   },
   {
     "df_mirror_rotating_16",
     "df_mirror_rotating",
-    "rotating mirror (168.75\xb0)"
+    "Rotating mirror (168.75\xb0)"
   },
   {
     "df_wooden_grid_rotating_1",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (0\xb0)"
+    "Rotating wooden polarizer (0\xb0)"
   },
   {
     "df_wooden_grid_rotating_2",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (22.5\xb0)"
+    "Rotating wooden polarizer (22.5\xb0)"
   },
   {
     "df_wooden_grid_rotating_3",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (45\xb0)"
+    "Rotating wooden polarizer (45\xb0)"
   },
   {
     "df_wooden_grid_rotating_4",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (67.5\xb0)"
+    "Rotating wooden polarizer (67.5\xb0)"
   },
   {
     "df_wooden_grid_rotating_5",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (90\xb0)"
+    "Rotating wooden polarizer (90\xb0)"
   },
   {
     "df_wooden_grid_rotating_6",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (112.5\xb0)"
+    "Rotating wooden polarizer (112.5\xb0)"
   },
   {
     "df_wooden_grid_rotating_7",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (135\xb0)"
+    "Rotating wooden polarizer (135\xb0)"
   },
   {
     "df_wooden_grid_rotating_8",
     "df_wooden_grid_rotating",
-    "rotating wooden polarizer (157.5\xb0)"
+    "Rotating wooden polarizer (157.5\xb0)"
   },
   {
     "df_steel_grid_rotating_1",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (0\xb0)"
+    "Rotating steel polarizer (0\xb0)"
   },
   {
     "df_steel_grid_rotating_2",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (22.5\xb0)"
+    "Rotating steel polarizer (22.5\xb0)"
   },
   {
     "df_steel_grid_rotating_3",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (45\xb0)"
+    "Rotating steel polarizer (45\xb0)"
   },
   {
     "df_steel_grid_rotating_4",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (67.5\xb0)"
+    "Rotating steel polarizer (67.5\xb0)"
   },
   {
     "df_steel_grid_rotating_5",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (90\xb0)"
+    "Rotating steel polarizer (90\xb0)"
   },
   {
     "df_steel_grid_rotating_6",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (112.5\xb0)"
+    "Rotating steel polarizer (112.5\xb0)"
   },
   {
     "df_steel_grid_rotating_7",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (135\xb0)"
+    "Rotating steel polarizer (135\xb0)"
   },
   {
     "df_steel_grid_rotating_8",
     "df_steel_grid_rotating",
-    "rotating steel polarizer (157.5\xb0)"
+    "Rotating steel polarizer (157.5\xb0)"
   },
   {
     "mm_teleporter_red_1",
     "mm_teleporter",
-    "red teleporter (0\xb0)"
+    "Red teleporter (0\xb0)"
   },
   {
     "mm_teleporter_red_2",
     "mm_teleporter",
-    "red teleporter (22.5\xb0)"
+    "Red teleporter (22.5\xb0)"
   },
   {
     "mm_teleporter_red_3",
     "mm_teleporter",
-    "red teleporter (45\xb0)"
+    "Red teleporter (45\xb0)"
   },
   {
     "mm_teleporter_red_4",
     "mm_teleporter",
-    "red teleporter (67.5\xb0)"
+    "Red teleporter (67.5\xb0)"
   },
   {
     "mm_teleporter_red_5",
     "mm_teleporter",
-    "red teleporter (90\xb0)"
+    "Red teleporter (90\xb0)"
   },
   {
     "mm_teleporter_red_6",
     "mm_teleporter",
-    "red teleporter (112.5\xb0)"
+    "Red teleporter (112.5\xb0)"
   },
   {
     "mm_teleporter_red_7",
     "mm_teleporter",
-    "red teleporter (135\xb0)"
+    "Red teleporter (135\xb0)"
   },
   {
     "mm_teleporter_red_8",
     "mm_teleporter",
-    "red teleporter (157.5\xb0)"
+    "Red teleporter (157.5\xb0)"
   },
   {
     "mm_teleporter_red_9",
     "mm_teleporter",
-    "red teleporter (180\xb0)"
+    "Red teleporter (180\xb0)"
   },
   {
     "mm_teleporter_red_10",
     "mm_teleporter",
-    "red teleporter (202.5\xb0)"
+    "Red teleporter (202.5\xb0)"
   },
   {
     "mm_teleporter_red_11",
     "mm_teleporter",
-    "red teleporter (225\xb0)"
+    "Red teleporter (225\xb0)"
   },
   {
     "mm_teleporter_red_12",
     "mm_teleporter",
-    "red teleporter (247.5\xb0)"
+    "Red teleporter (247.5\xb0)"
   },
   {
     "mm_teleporter_red_13",
     "mm_teleporter",
-    "red teleporter (270\xb0)"
+    "Red teleporter (270\xb0)"
   },
   {
     "mm_teleporter_red_14",
     "mm_teleporter",
-    "red teleporter (292.5\xb0)"
+    "Red teleporter (292.5\xb0)"
   },
   {
     "mm_teleporter_red_15",
     "mm_teleporter",
-    "red teleporter (315\xb0)"
+    "Red teleporter (315\xb0)"
   },
   {
     "mm_teleporter_red_16",
     "mm_teleporter",
-    "red teleporter (337.5\xb0)"
+    "Red teleporter (337.5\xb0)"
   },
   {
     "mm_teleporter_yellow_1",
     "mm_teleporter",
-    "yellow teleporter (0\xb0)"
+    "Yellow teleporter (0\xb0)"
   },
   {
     "mm_teleporter_yellow_2",
     "mm_teleporter",
-    "yellow teleporter (22.5\xb0)"
+    "Yellow teleporter (22.5\xb0)"
   },
   {
     "mm_teleporter_yellow_3",
     "mm_teleporter",
-    "yellow teleporter (45\xb0)"
+    "Yellow teleporter (45\xb0)"
   },
   {
     "mm_teleporter_yellow_4",
     "mm_teleporter",
-    "yellow teleporter (67.5\xb0)"
+    "Yellow teleporter (67.5\xb0)"
   },
   {
     "mm_teleporter_yellow_5",
     "mm_teleporter",
-    "yellow teleporter (90\xb0)"
+    "Yellow teleporter (90\xb0)"
   },
   {
     "mm_teleporter_yellow_6",
     "mm_teleporter",
-    "yellow teleporter (112.5\xb0)"
+    "Yellow teleporter (112.5\xb0)"
   },
   {
     "mm_teleporter_yellow_7",
     "mm_teleporter",
-    "yellow teleporter (135\xb0)"
+    "Yellow teleporter (135\xb0)"
   },
   {
     "mm_teleporter_yellow_8",
     "mm_teleporter",
-    "yellow teleporter (157.5\xb0)"
+    "Yellow teleporter (157.5\xb0)"
   },
   {
     "mm_teleporter_yellow_9",
     "mm_teleporter",
-    "yellow teleporter (180\xb0)"
+    "Yellow teleporter (180\xb0)"
   },
   {
     "mm_teleporter_yellow_10",
     "mm_teleporter",
-    "yellow teleporter (202.5\xb0)"
+    "Yellow teleporter (202.5\xb0)"
   },
   {
     "mm_teleporter_yellow_11",
     "mm_teleporter",
-    "yellow teleporter (225\xb0)"
+    "Yellow teleporter (225\xb0)"
   },
   {
     "mm_teleporter_yellow_12",
     "mm_teleporter",
-    "yellow teleporter (247.5\xb0)"
+    "Yellow teleporter (247.5\xb0)"
   },
   {
     "mm_teleporter_yellow_13",
     "mm_teleporter",
-    "yellow teleporter (270\xb0)"
+    "Yellow teleporter (270\xb0)"
   },
   {
     "mm_teleporter_yellow_14",
     "mm_teleporter",
-    "yellow teleporter (292.5\xb0)"
+    "Yellow teleporter (292.5\xb0)"
   },
   {
     "mm_teleporter_yellow_15",
     "mm_teleporter",
-    "yellow teleporter (315\xb0)"
+    "Yellow teleporter (315\xb0)"
   },
   {
     "mm_teleporter_yellow_16",
     "mm_teleporter",
-    "yellow teleporter (337.5\xb0)"
+    "Yellow teleporter (337.5\xb0)"
   },
   {
     "mm_teleporter_green_1",
     "mm_teleporter",
-    "green teleporter (0\xb0)"
+    "Green teleporter (0\xb0)"
   },
   {
     "mm_teleporter_green_2",
     "mm_teleporter",
-    "green teleporter (22.5\xb0)"
+    "Green teleporter (22.5\xb0)"
   },
   {
     "mm_teleporter_green_3",
     "mm_teleporter",
-    "green teleporter (45\xb0)"
+    "Green teleporter (45\xb0)"
   },
   {
     "mm_teleporter_green_4",
     "mm_teleporter",
-    "green teleporter (67.5\xb0)"
+    "Green teleporter (67.5\xb0)"
   },
   {
     "mm_teleporter_green_5",
     "mm_teleporter",
-    "green teleporter (90\xb0)"
+    "Green teleporter (90\xb0)"
   },
   {
     "mm_teleporter_green_6",
     "mm_teleporter",
-    "green teleporter (112.5\xb0)"
+    "Green teleporter (112.5\xb0)"
   },
   {
     "mm_teleporter_green_7",
     "mm_teleporter",
-    "green teleporter (135\xb0)"
+    "Green teleporter (135\xb0)"
   },
   {
     "mm_teleporter_green_8",
     "mm_teleporter",
-    "green teleporter (157.5\xb0)"
+    "Green teleporter (157.5\xb0)"
   },
   {
     "mm_teleporter_green_9",
     "mm_teleporter",
-    "green teleporter (180\xb0)"
+    "Green teleporter (180\xb0)"
   },
   {
     "mm_teleporter_green_10",
     "mm_teleporter",
-    "green teleporter (202.5\xb0)"
+    "Green teleporter (202.5\xb0)"
   },
   {
     "mm_teleporter_green_11",
     "mm_teleporter",
-    "green teleporter (225\xb0)"
+    "Green teleporter (225\xb0)"
   },
   {
     "mm_teleporter_green_12",
     "mm_teleporter",
-    "green teleporter (247.5\xb0)"
+    "Green teleporter (247.5\xb0)"
   },
   {
     "mm_teleporter_green_13",
     "mm_teleporter",
-    "green teleporter (270\xb0)"
+    "Green teleporter (270\xb0)"
   },
   {
     "mm_teleporter_green_14",
     "mm_teleporter",
-    "green teleporter (292.5\xb0)"
+    "Green teleporter (292.5\xb0)"
   },
   {
     "mm_teleporter_green_15",
     "mm_teleporter",
-    "green teleporter (315\xb0)"
+    "Green teleporter (315\xb0)"
   },
   {
     "mm_teleporter_green_16",
     "mm_teleporter",
-    "green teleporter (337.5\xb0)"
+    "Green teleporter (337.5\xb0)"
   },
   {
     "mm_teleporter_blue_1",
     "mm_teleporter",
-    "blue teleporter (0\xb0)"
+    "Blue teleporter (0\xb0)"
   },
   {
     "mm_teleporter_blue_2",
     "mm_teleporter",
-    "blue teleporter (22.5\xb0)"
+    "Blue teleporter (22.5\xb0)"
   },
   {
     "mm_teleporter_blue_3",
     "mm_teleporter",
-    "blue teleporter (45\xb0)"
+    "Blue teleporter (45\xb0)"
   },
   {
     "mm_teleporter_blue_4",
     "mm_teleporter",
-    "blue teleporter (67.5\xb0)"
+    "Blue teleporter (67.5\xb0)"
   },
   {
     "mm_teleporter_blue_5",
     "mm_teleporter",
-    "blue teleporter (90\xb0)"
+    "Blue teleporter (90\xb0)"
   },
   {
     "mm_teleporter_blue_6",
     "mm_teleporter",
-    "blue teleporter (112.5\xb0)"
+    "Blue teleporter (112.5\xb0)"
   },
   {
     "mm_teleporter_blue_7",
     "mm_teleporter",
-    "blue teleporter (135\xb0)"
+    "Blue teleporter (135\xb0)"
   },
   {
     "mm_teleporter_blue_8",
     "mm_teleporter",
-    "blue teleporter (157.5\xb0)"
+    "Blue teleporter (157.5\xb0)"
   },
   {
     "mm_teleporter_blue_9",
     "mm_teleporter",
-    "blue teleporter (180\xb0)"
+    "Blue teleporter (180\xb0)"
   },
   {
     "mm_teleporter_blue_10",
     "mm_teleporter",
-    "blue teleporter (202.5\xb0)"
+    "Blue teleporter (202.5\xb0)"
   },
   {
     "mm_teleporter_blue_11",
     "mm_teleporter",
-    "blue teleporter (225\xb0)"
+    "Blue teleporter (225\xb0)"
   },
   {
     "mm_teleporter_blue_12",
     "mm_teleporter",
-    "blue teleporter (247.5\xb0)"
+    "Blue teleporter (247.5\xb0)"
   },
   {
     "mm_teleporter_blue_13",
     "mm_teleporter",
-    "blue teleporter (270\xb0)"
+    "Blue teleporter (270\xb0)"
   },
   {
     "mm_teleporter_blue_14",
     "mm_teleporter",
-    "blue teleporter (292.5\xb0)"
+    "Blue teleporter (292.5\xb0)"
   },
   {
     "mm_teleporter_blue_15",
     "mm_teleporter",
-    "blue teleporter (315\xb0)"
+    "Blue teleporter (315\xb0)"
   },
   {
     "mm_teleporter_blue_16",
     "mm_teleporter",
-    "blue teleporter (337.5\xb0)"
+    "Blue teleporter (337.5\xb0)"
   },
   {
     "mm_mcduffin",
@@ -6220,443 +6225,1873 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "mm_pacman",
     "mm_pacman",
-    "pac man (MM style)"
+    "Pac man (MM style)"
   },
   {
     "mm_fuse",
     "mm_fuse",
-    "fuse (off)",
+    "Fuse (off)",
   },
   {
     "mm_steel_wall",
     "mm_steel_wall",
-    "steel wall (MM style)",
+    "Steel wall (MM style)",
   },
   {
     "mm_wooden_wall",
     "mm_wooden_wall",
-    "wooden wall (MM style)",
+    "Wooden wall (MM style)",
   },
   {
     "mm_ice_wall",
     "mm_ice_wall",
-    "ice wall",
+    "Ice wall",
   },
   {
     "mm_amoeba_wall",
     "mm_amoeba_wall",
-    "amoeba wall",
+    "Amoeba wall",
   },
   {
     "df_laser",
     "df_laser",
-    "laser cannon"
+    "Laser cannon"
   },
   {
     "df_receiver",
     "df_receiver",
-    "laser receiver"
+    "Laser receiver"
   },
   {
     "df_steel_wall",
     "df_steel_wall",
-    "steel wall (DF style)",
+    "Steel wall (DF style)",
   },
   {
     "df_wooden_wall",
     "df_wooden_wall",
-    "wooden wall (DF style)",
+    "Wooden wall (DF style)",
   },
   {
     "spring.left",
     "spring",
-    "spring (starts moving left)"
+    "Spring (starts moving left)"
   },
   {
     "spring.right",
     "spring",
-    "spring (starts moving right)"
+    "Spring (starts moving right)"
   },
-
-  // --------------------------------------------------------------------------
-  // "real" (and therefore drawable) runtime elements
-  // --------------------------------------------------------------------------
-
   {
-    "dynabomb_player_1.active",
-    "dynabomb",
-    "-"
+    "empty_space_1",
+    "empty_space",
+    "Empty space 1"
   },
   {
-    "dynabomb_player_2.active",
-    "dynabomb",
-    "-"
+    "empty_space_2",
+    "empty_space",
+    "Empty space 2"
   },
   {
-    "dynabomb_player_3.active",
-    "dynabomb",
-    "-"
+    "empty_space_3",
+    "empty_space",
+    "Empty space 3"
   },
   {
-    "dynabomb_player_4.active",
-    "dynabomb",
-    "-"
+    "empty_space_4",
+    "empty_space",
+    "Empty space 4"
   },
   {
-    "sp_disk_red.active",
-    "dynamite",
-    "-"
+    "empty_space_5",
+    "empty_space",
+    "Empty space 5"
   },
   {
-    "switchgate.opening",
-    "switchgate",
-    "-"
+    "empty_space_6",
+    "empty_space",
+    "Empty space 6"
   },
   {
-    "switchgate.closing",
-    "switchgate",
-    "-"
+    "empty_space_7",
+    "empty_space",
+    "Empty space 7"
   },
   {
-    "timegate.opening",
-    "timegate",
-    "-"
+    "empty_space_8",
+    "empty_space",
+    "Empty space 8"
   },
   {
-    "timegate.closing",
-    "timegate",
-    "-"
+    "empty_space_9",
+    "empty_space",
+    "Empty space 9"
   },
   {
-    "pearl.breaking",
-    "pearl",
-    "-"
+    "empty_space_10",
+    "empty_space",
+    "Empty space 10"
   },
   {
-    "trap.active",
-    "trap",
-    "-"
+    "empty_space_11",
+    "empty_space",
+    "Empty space 11"
   },
   {
-    "invisible_steelwall.active",
-    "steelwall",
-    "-"
+    "empty_space_12",
+    "empty_space",
+    "Empty space 12"
   },
   {
-    "invisible_wall.active",
-    "wall",
-    "-"
+    "empty_space_13",
+    "empty_space",
+    "Empty space 13"
   },
   {
-    "invisible_sand.active",
-    "sand",
-    "-"
+    "empty_space_14",
+    "empty_space",
+    "Empty space 14"
   },
   {
-    "conveyor_belt_1_left.active",
-    "conveyor_belt",
-    "-"
+    "empty_space_15",
+    "empty_space",
+    "Empty space 15"
   },
   {
-    "conveyor_belt_1_middle.active",
-    "conveyor_belt",
-    "-"
+    "empty_space_16",
+    "empty_space",
+    "Empty space 16"
   },
   {
-    "conveyor_belt_1_right.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_1",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (0\xb0)"
   },
   {
-    "conveyor_belt_2_left.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_2",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (11.25\xb0)"
   },
   {
-    "conveyor_belt_2_middle.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_3",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (22.5\xb0)"
   },
   {
-    "conveyor_belt_2_right.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_4",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (33.75\xb0)"
   },
   {
-    "conveyor_belt_3_left.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_5",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (45\xb0)"
   },
   {
-    "conveyor_belt_3_middle.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_6",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (56.25\xb0)"
   },
   {
-    "conveyor_belt_3_right.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_7",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (67.5\xb0)"
   },
   {
-    "conveyor_belt_4_left.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_8",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (78.75\xb0)"
   },
   {
-    "conveyor_belt_4_middle.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_9",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (90\xb0)"
   },
   {
-    "conveyor_belt_4_right.active",
-    "conveyor_belt",
-    "-"
+    "df_mirror_fixed_10",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (101.25\xb0)"
   },
   {
-    "exit.opening",
-    "exit",
-    "-"
+    "df_mirror_fixed_11",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (112.5\xb0)"
   },
   {
-    "exit.closing",
-    "exit",
-    "-"
+    "df_mirror_fixed_12",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (123.75\xb0)"
   },
   {
-    "steel_exit.opening",
-    "steel_exit",
-    "-"
+    "df_mirror_fixed_13",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (135\xb0)"
   },
   {
-    "steel_exit.closing",
-    "steel_exit",
-    "-"
+    "df_mirror_fixed_14",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (146.25\xb0)"
   },
   {
-    "em_exit.opening",
-    "em_exit",
-    "-"
+    "df_mirror_fixed_15",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (157.5\xb0)"
   },
   {
-    "em_exit.closing",
-    "em_exit",
-    "-"
+    "df_mirror_fixed_16",
+    "df_mirror_fixed",
+    "Fixed mirror (DF style) (168.75\xb0)"
   },
   {
-    "em_steel_exit.opening",
-    "em_steel_exit",
-    "-"
+    "df_slope_1",
+    "df_slope",
+    "Slope (DF style) (45\xb0)"
   },
   {
-    "em_steel_exit.closing",
-    "em_steel_exit",
-    "-"
+    "df_slope_2",
+    "df_slope",
+    "Slope (DF style) (135\xb0)"
   },
   {
-    "sp_exit.opening",
-    "sp_exit",
-    "-"
+    "df_slope_3",
+    "df_slope",
+    "Slope (DF style) (225\xb0)"
   },
   {
-    "sp_exit.closing",
-    "sp_exit",
-    "-"
+    "df_slope_4",
+    "df_slope",
+    "Slope (DF style) (315\xb0)"
   },
   {
-    "sp_exit_open",
-    "sp_exit",
-    "-"
+    "bdx_empty_space",
+    "empty_space",
+    "Empty space"
   },
   {
-    "sp_terminal.active",
-    "sp_terminal",
-    "-"
+    "bdx_sand_1",
+    "bdx_sand",
+    "Sand"
   },
   {
-    "sp_buggy_base.activating",
-    "sp_buggy_base",
-    "-"
+    "bdx_sand_2",
+    "bdx_sand",
+    "Sand 2"
   },
   {
-    "sp_buggy_base.active",
-    "sp_buggy_base",
-    "-"
+    "bdx_sand_ball",
+    "bdx_sand_ball",
+    "Sand ball"
   },
   {
-    "sp_murphy_clone",
-    "murphy_clone",
-    "-"
+    "bdx_sand_loose",
+    "bdx_sand_loose",
+    "Loose sand"
   },
   {
-    "amoeba.dropping",
-    "amoeba",
-    "-"
+    "bdx_sand_sloped_up_right",
+    "bdx_sand_sloped",
+    "Sand (sloped up right)"
   },
   {
-    "quicksand.emptying",
-    "quicksand",
-    "-"
+    "bdx_sand_sloped_up_left",
+    "bdx_sand_sloped",
+    "Sand (sloped up left)"
   },
   {
-    "quicksand_fast.emptying",
-    "quicksand",
-    "-"
+    "bdx_sand_sloped_down_left",
+    "bdx_sand_sloped",
+    "Sand (sloped down left)"
   },
   {
-    "magic_wall.active",
-    "magic_wall",
-    "-"
+    "bdx_sand_sloped_down_right",
+    "bdx_sand_sloped",
+    "Sand (sloped down right)"
   },
   {
-    "bd_magic_wall.active",
-    "magic_wall",
-    "-"
+    "bdx_sand_glued",
+    "bdx_sand_glued",
+    "Glued sand"
   },
   {
-    "dc_magic_wall.active",
-    "magic_wall",
-    "-"
+    "bdx_wall_sloped_up_right",
+    "bdx_wall_sloped",
+    "Wall (sloped up right)"
   },
   {
-    "magic_wall_full",
-    "magic_wall",
-    "-"
+    "bdx_wall_sloped_up_left",
+    "bdx_wall_sloped",
+    "Wall (sloped up left)"
   },
   {
-    "bd_magic_wall_full",
-    "magic_wall",
-    "-"
+    "bdx_wall_sloped_down_left",
+    "bdx_wall_sloped",
+    "Wall (sloped down left)"
   },
   {
-    "dc_magic_wall_full",
-    "magic_wall",
-    "-"
+    "bdx_wall_sloped_down_right",
+    "bdx_wall_sloped",
+    "Wall (sloped down right)"
   },
   {
-    "magic_wall.emptying",
-    "magic_wall",
-    "-"
+    "bdx_wall_non_sloped",
+    "bdx_wall",
+    "Wall (non sloped)"
   },
   {
-    "bd_magic_wall.emptying",
-    "magic_wall",
-    "-"
+    "bdx_wall_diggable",
+    "bdx_wall",
+    "Diggable wall"
   },
   {
-    "dc_magic_wall.emptying",
-    "magic_wall",
-    "-"
+    "bdx_wall_diamond",
+    "bdx_wall",
+    "Wall with diamond"
   },
   {
-    "magic_wall_dead",
-    "magic_wall",
-    "-"
+    "bdx_wall_key_1",
+    "bdx_wall",
+    "Wall with key 1"
   },
   {
-    "bd_magic_wall_dead",
-    "magic_wall",
-    "-"
+    "bdx_wall_key_2",
+    "bdx_wall",
+    "Wall with key 2"
   },
   {
-    "dc_magic_wall_dead",
-    "magic_wall",
-    "-"
+    "bdx_wall_key_3",
+    "bdx_wall",
+    "Wall with key 3"
   },
-
   {
-    "emc_fake_grass.active",
-    "fake_grass",
-    "-"
+    "bdx_falling_wall",
+    "bdx_wall",
+    "Falling wall"
   },
   {
-    "gate_1_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall",
+    "bdx_steelwall",
+    "Steel wall"
   },
   {
-    "gate_2_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_sloped_up_right",
+    "bdx_steelwall_sloped",
+    "Steel wall (sloped up right)"
   },
   {
-    "gate_3_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_sloped_up_left",
+    "bdx_steelwall_sloped",
+    "Steel wall (sloped up left)"
   },
   {
-    "gate_4_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_sloped_down_left",
+    "bdx_steelwall_sloped",
+    "Steel wall (sloped down left)"
   },
   {
-    "em_gate_1_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_sloped_down_right",
+    "bdx_steelwall_sloped",
+    "Steel wall (sloped down right)"
   },
   {
-    "em_gate_2_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_explodable",
+    "bdx_steelwall",
+    "Explodable steel wall"
   },
   {
-    "em_gate_3_gray.active",
-    "gate",
-    ""
+    "bdx_steelwall_diggable",
+    "bdx_steelwall",
+    "Diggable steel wall"
   },
   {
-    "em_gate_4_gray.active",
-    "gate",
-    ""
+    "bdx_expandable_wall_horizontal",
+    "bdx_expandable_wall",
+    "Expandable wall (horizontal)"
   },
   {
-    "emc_gate_5_gray.active",
-    "gate",
-    "",
+    "bdx_expandable_wall_vertical",
+    "bdx_expandable_wall",
+    "Expandable wall (vertical)"
   },
   {
-    "emc_gate_6_gray.active",
-    "gate",
-    "",
+    "bdx_expandable_wall_any",
+    "bdx_expandable_wall",
+    "Expandable wall (any direction)"
   },
   {
-    "emc_gate_7_gray.active",
-    "gate",
-    "",
+    "bdx_expandable_steelwall_horizontal",
+    "bdx_expandable_steelwall",
+    "Expandable steelwall (horizontal)"
   },
   {
-    "emc_gate_8_gray.active",
-    "gate",
-    "",
+    "bdx_expandable_steelwall_vertical",
+    "bdx_expandable_steelwall",
+    "Expandable steelwall (vertical)"
   },
   {
-    "dc_gate_white_gray.active",
-    "gate",
-    "",
+    "bdx_expandable_steelwall_any",
+    "bdx_expandable_steelwall",
+    "Expandable steelwall (any direction)"
   },
   {
-    "emc_dripper.active",
-    "dripper",
-    "dripper"
+    "bdx_expandable_wall_switch",
+    "bdx_expandable_wall_switch",
+    "Expandable wall switch"
   },
   {
-    "emc_spring_bumper.active",
-    "emc_spring_bumper",
-    "spring bumper",
+    "bdx_expandable_wall_switch.active",
+    "bdx_expandable_wall_switch",
+    "Expandable wall switch (active)"
   },
   {
-    "mm_exit.opening",
-    "mm_exit",
-    "-"
+    "bdx_inbox",
+    "bdx_inbox",
+    "Inbox with player"
   },
   {
-    "mm_exit.closing",
-    "mm_exit",
-    "-"
+    "bdx_exit_closed",
+    "bdx_exit",
+    "Closed exit"
   },
   {
-    "mm_gray_ball.opening",
-    "mm_gray_ball",
-    "-",
+    "bdx_exit_open",
+    "bdx_exit",
+    "Open exit"
+  },
+  {
+    "bdx_invisible_exit_closed",
+    "bdx_invisible_exit",
+    "Invisible exit (closed)"
+  },
+  {
+    "bdx_invisible_exit_open",
+    "bdx_invisible_exit",
+    "Invisible exit (open)"
+  },
+  {
+    "bdx_flying_rock",
+    "bdx_flying_rock",
+    "Flying rock"
+  },
+  {
+    "bdx_mega_rock",
+    "bdx_mega_rock",
+    "Mega rock"
+  },
+  {
+    "bdx_rock_glued",
+    "bdx_rock_glued",
+    "Glued rock"
+  },
+  {
+    "bdx_flying_diamond",
+    "bdx_flying_diamond",
+    "Flying diamond"
+  },
+  {
+    "bdx_diamond_glued",
+    "bdx_diamond_glued",
+    "Glued diamond"
+  },
+  {
+    "bdx_diamond_key",
+    "bdx_diamond_key",
+    "Diamond key"
+  },
+  {
+    "bdx_trapped_diamond",
+    "bdx_trapped_diamond",
+    "Trapped diamond"
+  },
+  {
+    "bdx_nut",
+    "bdx_nut",
+    "Nut"
+  },
+  {
+    "bdx_amoeba_1",
+    "bdx_amoeba",
+    "Amoeba 1"
+  },
+  {
+    "bdx_amoeba_2",
+    "bdx_amoeba",
+    "Amoeba 2"
+  },
+  {
+    "bdx_bladder",
+    "bdx_bladder",
+    "Bladder"
+  },
+  {
+    "bdx_bladder_spender",
+    "bdx_bladder_spender",
+    "Bladder spender"
+  },
+  {
+    "bdx_creature_switch",
+    "bdx_creature_switch",
+    "Creature direction switch"
+  },
+  {
+    "bdx_creature_switch.active",
+    "bdx_creature_switch",
+    "Creature direction switch (active)"
+  },
+  {
+    "bdx_biter_switch_1",
+    "bdx_biter_switch",
+    "Biter switch"
+  },
+  {
+    "bdx_biter_switch_2",
+    "bdx_biter_switch",
+    "Biter switch"
+  },
+  {
+    "bdx_biter_switch_3",
+    "bdx_biter_switch",
+    "Biter switch"
+  },
+  {
+    "bdx_biter_switch_4",
+    "bdx_biter_switch",
+    "Biter switch"
+  },
+  {
+    "bdx_replicator",
+    "bdx_replicator",
+    "Replicator"
+  },
+  {
+    "bdx_replicator.active",
+    "bdx_replicator",
+    "Replicator (active)"
+  },
+  {
+    "bdx_replicator_switch",
+    "bdx_replicator_switch",
+    "Replicator switch"
+  },
+  {
+    "bdx_replicator_switch.active",
+    "bdx_replicator_switch",
+    "Replicator switch (active)"
+  },
+  {
+    "bdx_conveyor_left",
+    "bdx_conveyor",
+    "Conveyor belt (moving left)"
+  },
+  {
+    "bdx_conveyor_left.active",
+    "bdx_conveyor",
+    "Conveyor belt (moving left) (active)"
+  },
+  {
+    "bdx_conveyor_right",
+    "bdx_conveyor",
+    "Conveyor belt (moving right)"
+  },
+  {
+    "bdx_conveyor_right.active",
+    "bdx_conveyor",
+    "Conveyor belt (moving right) (active)"
+  },
+  {
+    "bdx_conveyor_switch",
+    "bdx_conveyor_switch",
+    "Conveyor belt power switch"
+  },
+  {
+    "bdx_conveyor_switch.active",
+    "bdx_conveyor_switch",
+    "Conveyor belt power switch (active)"
+  },
+  {
+    "bdx_conveyor_dir_switch",
+    "bdx_conveyor_dir_switch",
+    "Conveyor belt direction switch"
+  },
+  {
+    "bdx_conveyor_dir_switch.active",
+    "bdx_conveyor_dir_switch",
+    "Conveyor belt direction switch (active)"
+  },
+  {
+    "bdx_gravity_switch",
+    "bdx_gravity_switch",
+    "Gravity switch"
+  },
+  {
+    "bdx_gravity_switch.active",
+    "bdx_gravity_switch",
+    "Gravity switch (active)"
+  },
+  {
+    "bdx_acid",
+    "bdx_acid",
+    "Acid"
+  },
+  {
+    "bdx_box",
+    "bdx_box",
+    "Box"
+  },
+  {
+    "bdx_time_penalty",
+    "bdx_time_penalty",
+    "Time penalty"
+  },
+  {
+    "bdx_gravestone",
+    "bdx_gravestone",
+    "Gravestone"
+  },
+  {
+    "bdx_clock",
+    "bdx_clock",
+    "Clock"
+  },
+  {
+    "bdx_pot",
+    "bdx_pot",
+    "Pot"
+  },
+  {
+    "bdx_pneumatic_hammer",
+    "bdx_pneumatic_hammer",
+    "Pneumatic hammer"
+  },
+  {
+    "bdx_teleporter",
+    "bdx_teleporter",
+    "Teleporter"
+  },
+  {
+    "bdx_skeleton",
+    "bdx_skeleton",
+    "Skeleton"
+  },
+  {
+    "bdx_water",
+    "bdx_water",
+    "Water"
+  },
+  {
+    "bdx_key_1",
+    "bdx_key",
+    "Key 1"
+    },
+  {
+    "bdx_key_2",
+    "bdx_key",
+    "Key 2"
+    },
+  {
+    "bdx_key_3",
+    "bdx_key",
+    "Key 3"
+  },
+  {
+    "bdx_gate_1",
+    "bdx_gate",
+    "Door 1"
+  },
+  {
+    "bdx_gate_2",
+    "bdx_gate",
+    "Door 2"
+  },
+  {
+    "bdx_gate_3",
+    "bdx_gate",
+    "Door 3"
+  },
+  {
+    "bdx_lava",
+    "bdx_lava",
+    "Lava"
+  },
+  {
+    "bdx_sweet",
+    "bdx_sweet",
+    "Sweet"
+  },
+  {
+    "bdx_voodoo_doll",
+    "bdx_voodoo_doll",
+    "Voodoo doll"
+  },
+  {
+    "bdx_slime",
+    "bdx_slime",
+    "Slime"
+  },
+  {
+    "bdx_waiting_rock",
+    "bdx_waiting_rock",
+    "Waiting rock"
+  },
+  {
+    "bdx_chasing_rock",
+    "bdx_chasing_rock",
+    "Chasing rock"
+  },
+  {
+    "bdx_ghost",
+    "bdx_ghost",
+    "Ghost"
+  },
+  {
+    "bdx_cow",
+    "bdx_cow",
+    "Cow (random start direction)"
+  },
+  {
+    "bdx_cow.left",
+    "bdx_cow",
+    "Cow (starts moving left)"
+  },
+  {
+    "bdx_cow.up",
+    "bdx_cow",
+    "Cow (starts moving up)"
+  },
+  {
+    "bdx_cow.right",
+    "bdx_cow",
+    "Cow (starts moving right)"
+  },
+  {
+    "bdx_cow.down",
+    "bdx_cow",
+    "Cow (starts moving down)"
+  },
+  {
+    "bdx_butterfly_1",
+    "bdx_butterfly",
+    "Butterfly 1 (random start direction)"
+  },
+  {
+    "bdx_butterfly_1.right",
+    "bdx_butterfly",
+    "Butterfly 1 (starts moving right)"
+  },
+  {
+    "bdx_butterfly_1.up",
+    "bdx_butterfly",
+    "Butterfly 1 (starts moving up)"
+  },
+  {
+    "bdx_butterfly_1.left",
+    "bdx_butterfly",
+    "Butterfly 1 (starts moving left)"
+  },
+  {
+    "bdx_butterfly_1.down",
+    "bdx_butterfly",
+    "Butterfly 1 (starts moving down)"
+  },
+  {
+    "bdx_butterfly_2",
+    "bdx_butterfly",
+    "Butterfly 2 (random start direction)"
+  },
+  {
+    "bdx_butterfly_2.right",
+    "bdx_butterfly",
+    "Butterfly 2 (starts moving right)"
+  },
+  {
+    "bdx_butterfly_2.up",
+    "bdx_butterfly",
+    "Butterfly 2 (starts moving up)"
+  },
+  {
+    "bdx_butterfly_2.left",
+    "bdx_butterfly",
+    "Butterfly 2 (starts moving left)"
+  },
+  {
+    "bdx_butterfly_2.down",
+    "bdx_butterfly",
+    "Butterfly 2 (starts moving down)"
+  },
+  {
+    "bdx_firefly_1",
+    "bdx_firefly",
+    "Firefly 1 (random start direction)"
+  },
+  {
+    "bdx_firefly_1.right",
+    "bdx_firefly",
+    "Firefly 1 (starts moving right)"
+  },
+  {
+    "bdx_firefly_1.up",
+    "bdx_firefly",
+    "Firefly 1 (starts moving up)"
+  },
+  {
+    "bdx_firefly_1.left",
+    "bdx_firefly",
+    "Firefly 1 (starts moving left)"
+  },
+  {
+    "bdx_firefly_1.down",
+    "bdx_firefly",
+    "Firefly 1 (starts moving down)"
+  },
+  {
+    "bdx_firefly_2",
+    "bdx_firefly",
+    "Firefly 2 (random start direction)"
+  },
+  {
+    "bdx_firefly_2.right",
+    "bdx_firefly",
+    "Firefly 2 (starts moving right)"
+  },
+  {
+    "bdx_firefly_2.up",
+    "bdx_firefly",
+    "Firefly 2 (starts moving up)"
+  },
+  {
+    "bdx_firefly_2.left",
+    "bdx_firefly",
+    "Firefly 2 (starts moving left)"
+  },
+  {
+    "bdx_firefly_2.down",
+    "bdx_firefly",
+    "Firefly 2 (starts moving down)"
+  },
+  {
+    "bdx_stonefly",
+    "bdx_stonefly",
+    "Stonefly (random start direction)"
+  },
+  {
+    "bdx_stonefly.right",
+    "bdx_stonefly",
+    "Stonefly (starts moving right)"
+  },
+  {
+    "bdx_stonefly.up",
+    "bdx_stonefly",
+    "Stonefly (starts moving up)"
+  },
+  {
+    "bdx_stonefly.left",
+    "bdx_stonefly",
+    "Stonefly (starts moving left)"
+  },
+  {
+    "bdx_stonefly.down",
+    "bdx_stonefly",
+    "Stonefly (starts moving down)"
+  },
+  {
+    "bdx_biter",
+    "bdx_biter",
+    "Biter (random start direction)"
+  },
+  {
+    "bdx_biter.right",
+    "bdx_biter",
+    "Biter (starts moving right)"
+  },
+  {
+    "bdx_biter.up",
+    "bdx_biter",
+    "Biter (starts moving up)"
+  },
+  {
+    "bdx_biter.left",
+    "bdx_biter",
+    "Biter (starts moving left)"
+  },
+  {
+    "bdx_biter.down",
+    "bdx_biter",
+    "Biter (starts moving down)"
+  },
+  {
+    "bdx_dragonfly",
+    "bdx_dragonfly",
+    "Dragonfly (random start direction)"
+  },
+  {
+    "bdx_dragonfly.right",
+    "bdx_dragonfly",
+    "Dragonfly (starts moving right)"
+  },
+  {
+    "bdx_dragonfly.up",
+    "bdx_dragonfly",
+    "Dragonfly (starts moving up)"
+  },
+  {
+    "bdx_dragonfly.left",
+    "bdx_dragonfly",
+    "Dragonfly (starts moving left)"
+  },
+  {
+    "bdx_dragonfly.down",
+    "bdx_dragonfly",
+    "Dragonfly (starts moving down)"
+  },
+  {
+    "bdx_bomb",
+    "bdx_bomb",
+    "Bomb"
+  },
+  {
+    "bdx_nitro_pack",
+    "bdx_nitro_pack",
+    "Nitro pack"
+  },
+  {
+    "bdx_player",
+    "bdx_player",
+    "Player"
+  },
+  {
+    "bdx_player_with_bomb",
+    "bdx_player",
+    "Player with bomb",
+  },
+  {
+    "bdx_player_with_rocket_launcher",
+    "bdx_player",
+    "Player with rocket launcher",
+  },
+  {
+    "bdx_player_glued",
+    "bdx_player",
+    "Glued player",
+  },
+  {
+    "bdx_player_stirring",
+    "bdx_player",
+    "Stirring player"
+  },
+  {
+    "bdx_rocket_launcher",
+    "bdx_rocket_launcher",
+    "Rocket launcher",
+  },
+  {
+    "bdx_rocket",
+    "bdx_rocket",
+    "Rocket",
+  },
+  {
+    "bdx_rocket.right",
+    "bdx_rocket",
+    "Rocket (starts moving right)"
+  },
+  {
+    "bdx_rocket.up",
+    "bdx_rocket",
+    "Rocket (starts moving up)"
+  },
+  {
+    "bdx_rocket.left",
+    "bdx_rocket",
+    "Rocket (starts moving left)"
+  },
+  {
+    "bdx_rocket.down",
+    "bdx_rocket",
+    "Rocket (starts moving down)"
+  },
+  {
+    "bdx_fake_bonus",
+    "bdx_fake_bonus",
+    "Fake bonus"
+  },
+  {
+    "bdx_covered",
+    "bdx_covered",
+    "Covered"
+  },
+  {
+    "bdx_wall",
+    "wall",
+    "Normal wall"
+  },
+  {
+    "bdx_rock",
+    "bdx_rock",
+    "Rock"
+  },
+  {
+    "bdx_diamond",
+    "bdx_diamond",
+    "Diamond"
+  },
+  {
+    "bdx_magic_wall",
+    "bdx_magic_wall",
+    "Magic wall"
+  },
+  {
+    "bdx_sand_ball.falling",
+    "bdx_sand_ball",
+    "Sand ball (falling)"
+  },
+  {
+    "bdx_sand_loose.falling",
+    "bdx_sand_loose",
+    "Loose sand (falling)"
+  },
+  {
+    "bdx_rock.falling",
+    "bdx_rock",
+    "Rock (falling)"
+  },
+  {
+    "bdx_flying_rock.flying",
+    "bdx_flying_rock",
+    "Flying rock (flying)"
+  },
+  {
+    "bdx_mega_rock.falling",
+    "bdx_mega_rock",
+    "Mega rock (falling)"
+  },
+  {
+    "bdx_diamond.falling",
+    "bdx_diamond",
+    "Diamond (falling)"
+  },
+  {
+    "bdx_flying_diamond.flying",
+    "bdx_flying_diamond",
+    "Flying diamond (flying)"
+  },
+  {
+    "bdx_nut.falling",
+    "bdx_nut",
+    "Nut (falling)"
+  },
+  {
+    "bdx_falling_wall.falling",
+    "bdx_wall",
+    "Falling wall (falling)"
+  },
+  {
+    "bdx_nitro_pack.falling",
+    "bdx_nitro_pack",
+    "Nitro pack (falling)"
+  },
+  {
+    "bdx_water_1",
+    "bdx_water",
+    "Water (1)"
+  },
+  {
+    "bdx_water_2",
+    "bdx_water",
+    "Water (2)"
+  },
+  {
+    "bdx_water_3",
+    "bdx_water",
+    "Water (3)"
+  },
+  {
+    "bdx_water_4",
+    "bdx_water",
+    "Water (4)"
+  },
+  {
+    "bdx_water_5",
+    "bdx_water",
+    "Water (5)"
+  },
+  {
+    "bdx_water_6",
+    "bdx_water",
+    "Water (6)"
+  },
+  {
+    "bdx_water_7",
+    "bdx_water",
+    "Water (7)"
+  },
+  {
+    "bdx_water_8",
+    "bdx_water",
+    "Water (8)"
+  },
+  {
+    "bdx_water_9",
+    "bdx_water",
+    "Water (9)"
+  },
+  {
+    "bdx_water_10",
+    "bdx_water",
+    "Water (10)"
+  },
+  {
+    "bdx_water_11",
+    "bdx_water",
+    "Water (11)"
+  },
+  {
+    "bdx_water_12",
+    "bdx_water",
+    "Water (12)"
+  },
+  {
+    "bdx_water_13",
+    "bdx_water",
+    "Water (13)"
+  },
+  {
+    "bdx_water_14",
+    "bdx_water",
+    "Water (14)"
+  },
+  {
+    "bdx_water_15",
+    "bdx_water",
+    "Water (15)"
+  },
+  {
+    "bdx_water_16",
+    "bdx_water",
+    "Water (16)"
+  },
+  {
+    "bdx_cow_enclosed_1",
+    "bdx_cow",
+    "Enclosed cow (1)"
+  },
+  {
+    "bdx_cow_enclosed_2",
+    "bdx_cow",
+    "Enclosed cow (2)"
+  },
+  {
+    "bdx_cow_enclosed_3",
+    "bdx_cow",
+    "Enclosed cow (3)"
+  },
+  {
+    "bdx_cow_enclosed_4",
+    "bdx_cow",
+    "Enclosed cow (4)"
+  },
+  {
+    "bdx_cow_enclosed_5",
+    "bdx_cow",
+    "Enclosed cow (5)"
+  },
+  {
+    "bdx_cow_enclosed_6",
+    "bdx_cow",
+    "Enclosed cow (6)"
+  },
+  {
+    "bdx_cow_enclosed_7",
+    "bdx_cow",
+    "Enclosed cow (7)"
+  },
+  {
+    "bdx_bladder_1",
+    "bdx_bladder",
+    "Bladder (1)"
+  },
+  {
+    "bdx_bladder_2",
+    "bdx_bladder",
+    "Bladder (2)"
+  },
+  {
+    "bdx_bladder_3",
+    "bdx_bladder",
+    "Bladder (3)"
+  },
+  {
+    "bdx_bladder_4",
+    "bdx_bladder",
+    "Bladder (4)"
+  },
+  {
+    "bdx_bladder_5",
+    "bdx_bladder",
+    "Bladder (5)"
+  },
+  {
+    "bdx_bladder_6",
+    "bdx_bladder",
+    "Bladder (6)"
+  },
+  {
+    "bdx_bladder_7",
+    "bdx_bladder",
+    "Bladder (7)"
+  },
+  {
+    "bdx_bladder_8",
+    "bdx_bladder",
+    "Bladder (8)"
+  },
+  {
+    "bdx_player.growing_1",
+    "bdx_player",
+    "Player birth (1)"
+  },
+  {
+    "bdx_player.growing_2",
+    "bdx_player",
+    "Player birth (2)"
+  },
+  {
+    "bdx_player.growing_3",
+    "bdx_player",
+    "Player birth (3)"
+  },
+  {
+    "bdx_bomb.ticking_1",
+    "bdx_bomb",
+    "Ticking bomb (1)"
+  },
+  {
+    "bdx_bomb.ticking_2",
+    "bdx_bomb",
+    "Ticking bomb (2)"
+  },
+  {
+    "bdx_bomb.ticking_3",
+    "bdx_bomb",
+    "Ticking bomb (3)"
+  },
+  {
+    "bdx_bomb.ticking_4",
+    "bdx_bomb",
+    "Ticking bomb (4)"
+  },
+  {
+    "bdx_bomb.ticking_5",
+    "bdx_bomb",
+    "Ticking bomb (5)"
+  },
+  {
+    "bdx_bomb.ticking_6",
+    "bdx_bomb",
+    "Ticking bomb (6)"
+  },
+  {
+    "bdx_bomb.ticking_7",
+    "bdx_bomb",
+    "Ticking bomb (7)"
+  },
+  {
+    "bdx_clock.growing_1",
+    "bdx_clock",
+    "Clock birth (1)"
+  },
+  {
+    "bdx_clock.growing_2",
+    "bdx_clock",
+    "Clock birth (2)"
+  },
+  {
+    "bdx_clock.growing_3",
+    "bdx_clock",
+    "Clock birth (3)"
+  },
+  {
+    "bdx_clock.growing_4",
+    "bdx_clock",
+    "Clock birth (4)"
+  },
+  {
+    "bdx_diamond.growing_1",
+    "bdx_diamond",
+    "Diamond birth (1)"
+  },
+  {
+    "bdx_diamond.growing_2",
+    "bdx_diamond",
+    "Diamond birth (2)"
+  },
+  {
+    "bdx_diamond.growing_3",
+    "bdx_diamond",
+    "Diamond birth (3)"
+  },
+  {
+    "bdx_diamond.growing_4",
+    "bdx_diamond",
+    "Diamond birth (4)"
+  },
+  {
+    "bdx_diamond.growing_5",
+    "bdx_diamond",
+    "Diamond birth (5)"
+  },
+  {
+    "bdx_exploding_1",
+    "bdx_exploding",
+    "Explosion (1)"
+  },
+  {
+    "bdx_exploding_2",
+    "bdx_exploding",
+    "Explosion (2)"
+  },
+  {
+    "bdx_exploding_3",
+    "bdx_exploding",
+    "Explosion (3)"
+  },
+  {
+    "bdx_exploding_4",
+    "bdx_exploding",
+    "Explosion (4)"
+  },
+  {
+    "bdx_exploding_5",
+    "bdx_exploding",
+    "Explosion (5)"
+  },
+  {
+    "bdx_rock.growing_1",
+    "bdx_rock",
+    "Rock birth (1)"
+  },
+  {
+    "bdx_rock.growing_2",
+    "bdx_rock",
+    "Rock birth (2)"
+  },
+  {
+    "bdx_rock.growing_3",
+    "bdx_rock",
+    "Rock birth (3)"
+  },
+  {
+    "bdx_rock.growing_4",
+    "bdx_rock",
+    "Rock birth (4)"
+  },
+  {
+    "bdx_steelwall.growing_1",
+    "bdx_steelwall",
+    "Steelwall birth (1)"
+  },
+  {
+    "bdx_steelwall.growing_2",
+    "bdx_steelwall",
+    "Steelwall birth (2)"
+  },
+  {
+    "bdx_steelwall.growing_3",
+    "bdx_steelwall",
+    "Steelwall birth (3)"
+  },
+  {
+    "bdx_steelwall.growing_4",
+    "bdx_steelwall",
+    "Steelwall birth (4)"
+  },
+  {
+    "bdx_ghost.exploding_1",
+    "bdx_ghost",
+    "Ghost explosion (1)"
+  },
+  {
+    "bdx_ghost.exploding_2",
+    "bdx_ghost",
+    "Ghost explosion (2)"
+  },
+  {
+    "bdx_ghost.exploding_3",
+    "bdx_ghost",
+    "Ghost explosion (3)"
+  },
+  {
+    "bdx_ghost.exploding_4",
+    "bdx_ghost",
+    "Ghost explosion (4)"
+  },
+  {
+    "bdx_bomb.exploding_1",
+    "bdx_bomb",
+    "Bomb explosion (1)"
+  },
+  {
+    "bdx_bomb.exploding_2",
+    "bdx_bomb",
+    "Bomb explosion (2)"
+  },
+  {
+    "bdx_bomb.exploding_3",
+    "bdx_bomb",
+    "Bomb explosion (3)"
+  },
+  {
+    "bdx_bomb.exploding_4",
+    "bdx_bomb",
+    "Bomb explosion (4)"
+  },
+  {
+    "bdx_nitro_pack.exploding",
+    "bdx_nitro_pack",
+    "Nitro pack (triggered)"
+  },
+  {
+    "bdx_nitro_pack.exploding_1",
+    "bdx_nitro_pack",
+    "Nitro pack explosion (1)"
+  },
+  {
+    "bdx_nitro_pack.exploding_2",
+    "bdx_nitro_pack",
+    "Nitro pack explosion (2)"
+  },
+  {
+    "bdx_nitro_pack.exploding_3",
+    "bdx_nitro_pack",
+    "Nitro pack explosion (3)"
+  },
+  {
+    "bdx_nitro_pack.exploding_4",
+    "bdx_nitro_pack",
+    "Nitro pack explosion (4)"
+  },
+  {
+    "bdx_amoeba_2.exploding_1",
+    "bdx_amoeba",
+    "Amoeba 2 explosion (1)"
+  },
+  {
+    "bdx_amoeba_2.exploding_2",
+    "bdx_amoeba",
+    "Amoeba 2 explosion (2)"
+  },
+  {
+    "bdx_amoeba_2.exploding_3",
+    "bdx_amoeba",
+    "Amoeba 2 explosion (3)"
+  },
+  {
+    "bdx_amoeba_2.exploding_4",
+    "bdx_amoeba",
+    "Amoeba 2 explosion (4)"
+  },
+  {
+    "bdx_nut.breaking_1",
+    "bdx_nut",
+    "Nut explosion (1)"
+  },
+  {
+    "bdx_nut.breaking_2",
+    "bdx_nut",
+    "Nut explosion (2)"
+  },
+  {
+    "bdx_nut.breaking_3",
+    "bdx_nut",
+    "Nut explosion (3)"
+  },
+  {
+    "bdx_nut.breaking_4",
+    "bdx_nut",
+    "Nut explosion (4)"
+  },
+
+  // --------------------------------------------------------------------------
+  // "real" (and therefore drawable) runtime elements
+  // --------------------------------------------------------------------------
+
+  {
+    "dynabomb_player_1.active",
+    "dynabomb",
+    "-"
+  },
+  {
+    "dynabomb_player_2.active",
+    "dynabomb",
+    "-"
+  },
+  {
+    "dynabomb_player_3.active",
+    "dynabomb",
+    "-"
+  },
+  {
+    "dynabomb_player_4.active",
+    "dynabomb",
+    "-"
+  },
+  {
+    "sp_disk_red.active",
+    "dynamite",
+    "-"
+  },
+  {
+    "switchgate.opening",
+    "switchgate",
+    "-"
+  },
+  {
+    "switchgate.closing",
+    "switchgate",
+    "-"
+  },
+  {
+    "timegate.opening",
+    "timegate",
+    "-"
+  },
+  {
+    "timegate.closing",
+    "timegate",
+    "-"
+  },
+  {
+    "pearl.breaking",
+    "pearl",
+    "-"
+  },
+  {
+    "trap.active",
+    "trap",
+    "-"
+  },
+  {
+    "invisible_steelwall.active",
+    "steelwall",
+    "-"
+  },
+  {
+    "invisible_wall.active",
+    "wall",
+    "-"
+  },
+  {
+    "invisible_sand.active",
+    "sand",
+    "-"
+  },
+  {
+    "conveyor_belt_1_left.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_1_middle.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_1_right.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_2_left.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_2_middle.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_2_right.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_3_left.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_3_middle.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_3_right.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_4_left.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_4_middle.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "conveyor_belt_4_right.active",
+    "conveyor_belt",
+    "-"
+  },
+  {
+    "exit.opening",
+    "exit",
+    "-"
+  },
+  {
+    "exit.closing",
+    "exit",
+    "-"
+  },
+  {
+    "steel_exit.opening",
+    "steel_exit",
+    "-"
+  },
+  {
+    "steel_exit.closing",
+    "steel_exit",
+    "-"
+  },
+  {
+    "em_exit.opening",
+    "em_exit",
+    "-"
+  },
+  {
+    "em_exit.closing",
+    "em_exit",
+    "-"
+  },
+  {
+    "em_steel_exit.opening",
+    "em_steel_exit",
+    "-"
+  },
+  {
+    "em_steel_exit.closing",
+    "em_steel_exit",
+    "-"
+  },
+  {
+    "sp_exit.opening",
+    "sp_exit",
+    "-"
+  },
+  {
+    "sp_exit.closing",
+    "sp_exit",
+    "-"
+  },
+  {
+    "sp_exit_open",
+    "sp_exit",
+    "-"
+  },
+  {
+    "sp_terminal.active",
+    "sp_terminal",
+    "-"
+  },
+  {
+    "sp_buggy_base.activating",
+    "sp_buggy_base",
+    "-"
+  },
+  {
+    "sp_buggy_base.active",
+    "sp_buggy_base",
+    "-"
+  },
+  {
+    "sp_murphy_clone",
+    "murphy_clone",
+    "-"
+  },
+  {
+    "amoeba.dropping",
+    "amoeba",
+    "-"
+  },
+  {
+    "quicksand.emptying",
+    "quicksand",
+    "-"
+  },
+  {
+    "quicksand_fast.emptying",
+    "quicksand",
+    "-"
+  },
+  {
+    "magic_wall.active",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall.active",
+    "magic_wall",
+    "-"
+  },
+  {
+    "dc_magic_wall.active",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall_full",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_full",
+    "magic_wall",
+    "-"
+  },
+  {
+    "dc_magic_wall_full",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall.emptying",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall.emptying",
+    "magic_wall",
+    "-"
+  },
+  {
+    "dc_magic_wall.emptying",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall_dead",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_dead",
+    "magic_wall",
+    "-"
+  },
+  {
+    "dc_magic_wall_dead",
+    "magic_wall",
+    "-"
+  },
+
+  {
+    "emc_fake_grass.active",
+    "fake_grass",
+    "-"
+  },
+  {
+    "gate_1_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_2_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_3_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_4_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_1_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_2_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_3_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_4_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "emc_gate_5_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_6_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_7_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_8_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "dc_gate_white_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_dripper.active",
+    "dripper",
+    "Dripper"
+  },
+  {
+    "emc_spring_bumper.active",
+    "emc_spring_bumper",
+    "Spring bumper",
+  },
+  {
+    "mm_exit.opening",
+    "mm_exit",
+    "-"
+  },
+  {
+    "mm_exit.closing",
+    "mm_exit",
+    "-"
+  },
+  {
+    "mm_gray_ball.active",
+    "mm_gray_ball",
+    "-",
+  },
+  {
+    "mm_gray_ball.opening",
+    "mm_gray_ball",
+    "-",
   },
   {
     "mm_ice_wall.shrinking",
@@ -6671,22 +8106,37 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "mm_pacman.eating.right",
     "mm_pacman",
-    "pac man (eating right)"
+    "Pac man (eating right)"
   },
   {
     "mm_pacman.eating.up",
     "mm_pacman",
-    "pac man (eating up)"
+    "Pac man (eating up)"
   },
   {
     "mm_pacman.eating.left",
     "mm_pacman",
-    "pac man (eating left)"
+    "Pac man (eating left)"
   },
   {
     "mm_pacman.eating.down",
     "mm_pacman",
-    "pac man (eating down)"
+    "Pac man (eating down)"
+  },
+  {
+    "mm_bomb.active",
+    "mm_bomb",
+    "Active bomb (MM style)"
+  },
+  {
+    "df_mine.active",
+    "df_mine",
+    "Active mine"
+  },
+  {
+    "bdx_magic_wall.active",
+    "magic_wall",
+    "-"
   },
 
   // --------------------------------------------------------------------------
@@ -6938,56 +8388,6 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "-",
     "-"
   },
-  {
-    "mm_mask_mcduffin.right",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_mcduffin.up",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_mcduffin.left",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_mcduffin.down",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_grid_1",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_grid_2",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_grid_3",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_grid_4",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_rectangle",
-    "-",
-    "-"
-  },
-  {
-    "mm_mask_circle",
-    "-",
-    "-"
-  },
   {
     "[default]",
     "default",
@@ -6998,6 +8398,11 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "bd_default",
     "-"
   },
+  {
+    "[bdx_default]",
+    "bdx_default",
+    "-"
+  },
   {
     "[sp_default]",
     "sp_default",
@@ -7053,20 +8458,25 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "graphic",
     "-"
   },
+  {
+    "bdx_game_graphics_color_template",
+    "-",
+    "-"
+  },
   {
     "internal_clipboard_custom",
     "internal",
-    "empty custom element"
+    "Empty custom element"
   },
   {
     "internal_clipboard_change",
     "internal",
-    "empty change page"
+    "Empty change page"
   },
   {
     "internal_clipboard_group",
     "internal",
-    "empty group element"
+    "Empty group element"
   },
   {
     "internal_dummy",
@@ -7076,172 +8486,202 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "internal_cascade_bd",
     "internal",
-    "show Boulder Dash elements"
+    "Show Boulder Dash elements"
   },
   {
     "internal_cascade_bd.active",
     "internal",
-    "hide Boulder Dash elements"
+    "Hide Boulder Dash elements"
+  },
+  {
+    "internal_cascade_bdx",
+    "internal",
+    "Show Boulder Dash native elements"
+  },
+  {
+    "internal_cascade_bdx.active",
+    "internal",
+    "Hide Boulder Dash native elements"
+  },
+  {
+    "internal_cascade_bdx_effects",
+    "internal",
+    "Show Boulder Dash effects elements"
+  },
+  {
+    "internal_cascade_bdx_effects.active",
+    "internal",
+    "Hide Boulder Dash effects elements"
   },
   {
     "internal_cascade_em",
     "internal",
-    "show Emerald Mine elements"
+    "Show Emerald Mine elements"
   },
   {
     "internal_cascade_em.active",
     "internal",
-    "hide Emerald Mine elements"
+    "Hide Emerald Mine elements"
   },
   {
     "internal_cascade_emc",
     "internal",
-    "show Emerald Mine Club elements"
+    "Show Emerald Mine Club elements"
   },
   {
     "internal_cascade_emc.active",
     "internal",
-    "hide Emerald Mine Club elements"
+    "Hide Emerald Mine Club elements"
   },
   {
     "internal_cascade_rnd",
     "internal",
-    "show Rocks'n'Diamonds elements"
+    "Show Rocks'n'Diamonds elements"
   },
   {
     "internal_cascade_rnd.active",
     "internal",
-    "hide Rocks'n'Diamonds elements"
+    "Hide Rocks'n'Diamonds elements"
   },
   {
     "internal_cascade_sb",
     "internal",
-    "show Sokoban elements"
+    "Show Sokoban elements"
   },
   {
     "internal_cascade_sb.active",
     "internal",
-    "hide Sokoban elements"
+    "Hide Sokoban elements"
   },
   {
     "internal_cascade_sp",
     "internal",
-    "show Supaplex elements"
+    "Show Supaplex elements"
   },
   {
     "internal_cascade_sp.active",
     "internal",
-    "hide Supaplex elements"
+    "Hide Supaplex elements"
   },
   {
     "internal_cascade_dc",
     "internal",
-    "show Diamond Caves II elements"
+    "Show Diamond Caves II elements"
   },
   {
     "internal_cascade_dc.active",
     "internal",
-    "hide Diamond Caves II elements"
+    "Hide Diamond Caves II elements"
   },
   {
     "internal_cascade_dx",
     "internal",
-    "show DX Boulderdash elements"
+    "Show DX Boulderdash elements"
   },
   {
     "internal_cascade_dx.active",
     "internal",
-    "hide DX Boulderdash elements"
+    "Hide DX Boulderdash elements"
   },
   {
     "internal_cascade_mm",
     "internal",
-    "show Mirror Magic elements"
+    "Show Mirror Magic elements"
   },
   {
     "internal_cascade_mm.active",
     "internal",
-    "hide Mirror Magic elements"
+    "Hide Mirror Magic elements"
   },
   {
     "internal_cascade_df",
     "internal",
-    "show Deflektor elements"
+    "Show Deflektor elements"
   },
   {
     "internal_cascade_df.active",
     "internal",
-    "hide Deflektor elements"
+    "Hide Deflektor elements"
   },
   {
     "internal_cascade_chars",
     "internal",
-    "show text elements"
+    "Show text elements"
   },
   {
     "internal_cascade_chars.active",
     "internal",
-    "hide text elements"
+    "Hide text elements"
   },
   {
     "internal_cascade_steel_chars",
     "internal",
-    "show steel text elements"
+    "Show steel text elements"
   },
   {
     "internal_cascade_steel_chars.active",
     "internal",
-    "hide steel text elements"
+    "Hide steel text elements"
   },
   {
     "internal_cascade_ce",
     "internal",
-    "show custom elements"
+    "Show custom elements"
   },
   {
     "internal_cascade_ce.active",
     "internal",
-    "hide custom elements"
+    "Hide custom elements"
   },
   {
     "internal_cascade_ge",
     "internal",
-    "show group elements"
+    "Show group elements"
   },
   {
     "internal_cascade_ge.active",
     "internal",
-    "hide group elements"
+    "Hide group elements"
+  },
+  {
+    "internal_cascade_es",
+    "internal",
+    "Show empty space elements"
+  },
+  {
+    "internal_cascade_es.active",
+    "internal",
+    "Hide empty space elements"
   },
   {
     "internal_cascade_ref",
     "internal",
-    "show reference elements"
+    "Show reference elements"
   },
   {
     "internal_cascade_ref.active",
     "internal",
-    "hide reference elements"
+    "Hide reference elements"
   },
   {
     "internal_cascade_user",
     "internal",
-    "show user defined elements"
+    "Show user defined elements"
   },
   {
     "internal_cascade_user.active",
     "internal",
-    "hide user defined elements"
+    "Hide user defined elements"
   },
   {
     "internal_cascade_dynamic",
     "internal",
-    "show elements used in this level"
+    "Show elements used in this level"
   },
   {
     "internal_cascade_dynamic.active",
     "internal",
-    "hide elements used in this level"
+    "Hide elements used in this level"
   },
 
   // keyword to stop parser: "ELEMENT_INFO_END" <-- do not change!
@@ -7313,6 +8753,7 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
   { ".twinkling",              ACTION_TWINKLING,               FALSE   },
   { ".splashing",              ACTION_SPLASHING,               FALSE   },
   { ".hitting",                        ACTION_HITTING,                 FALSE   },
+  { ".flying",                 ACTION_FLYING,                  FALSE   },
   { ".page[1]",                        ACTION_PAGE_1,                  FALSE   },
   { ".page[2]",                        ACTION_PAGE_2,                  FALSE   },
   { ".page[3]",                        ACTION_PAGE_3,                  FALSE   },
@@ -7402,6 +8843,7 @@ struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS_FULL + 1] =
 struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
 {
   { ".[DEFAULT]",              GFX_SPECIAL_ARG_DEFAULT,                },
+  { ".LOADING_INITIAL",                GFX_SPECIAL_ARG_LOADING_INITIAL,        },
   { ".LOADING",                        GFX_SPECIAL_ARG_LOADING,                },
   { ".TITLE_INITIAL",          GFX_SPECIAL_ARG_TITLE_INITIAL,          },
   { ".TITLE_INITIAL_1",                GFX_SPECIAL_ARG_TITLE_INITIAL_1,        },
@@ -7420,6 +8862,7 @@ struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
   { ".LEVELS",                 GFX_SPECIAL_ARG_LEVELS                  },
   { ".LEVELNR",                        GFX_SPECIAL_ARG_LEVELNR                 },
   { ".SCORES",                 GFX_SPECIAL_ARG_SCORES,                 },
+  { ".SCOREINFO",              GFX_SPECIAL_ARG_SCOREINFO,              },
   { ".EDITOR",                 GFX_SPECIAL_ARG_EDITOR,                 },
   { ".INFO",                   GFX_SPECIAL_ARG_INFO,                   },
   { ".SETUP",                  GFX_SPECIAL_ARG_SETUP,                  },
@@ -7431,6 +8874,7 @@ struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
   { ".CRUMBLED",               GFX_SPECIAL_ARG_CRUMBLED,               },
   { ".MAINONLY",               GFX_SPECIAL_ARG_MAINONLY,               },
   { ".NAMESONLY",              GFX_SPECIAL_ARG_NAMESONLY,              },
+  { ".SCORESONLY",             GFX_SPECIAL_ARG_SCORESONLY,             },
   { ".TYPENAME",               GFX_SPECIAL_ARG_TYPENAME,               },
   { ".TYPENAMES",              GFX_SPECIAL_ARG_TYPENAMES,              },
   { ".SUBMENU",                        GFX_SPECIAL_ARG_SUBMENU,                },
@@ -7483,6 +8927,7 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { "font.envelope_2"          },
   { "font.envelope_3"          },
   { "font.envelope_4"          },
+  { "font.request_narrow"      },
   { "font.request"             },
   { "font.input_1.active"      },
   { "font.input_2.active"      },
@@ -7613,10 +9058,11 @@ static void print_usage(void)
        "\n"
        "Options:\n"
        "  -b, --basepath DIRECTORY         alternative base DIRECTORY\n"
-       "  -l, --level DIRECTORY            alternative level DIRECTORY\n"
+       "  -l, --levels DIRECTORY           alternative levels DIRECTORY\n"
        "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
        "  -s, --sounds DIRECTORY           alternative sounds DIRECTORY\n"
        "  -m, --music DIRECTORY            alternative music DIRECTORY\n"
+       "      --display NR                 open program window on display NR\n"
        "      --mytapes                    use private tapes for tape tests\n"
        "  -n, --network                    network multiplayer game\n"
        "      --serveronly                 only start network server\n"
@@ -7632,6 +9078,7 @@ static void print_usage(void)
        "  \"print editorsetup.conf\"         print default editor config\n"
        "  \"print helpanim.conf\"            print default helpanim config\n"
        "  \"print helptext.conf\"            print default helptext config\n"
+       "  \"dump levelset FILE|LEVELDIR\"    dump levelset info for LEVELDIR\n"
        "  \"dump level FILE\"                dump level data from FILE\n"
        "  \"dump tape FILE\"                 dump tape data from FILE\n"
        "  \"autoplay LEVELDIR [NR ...]\"     play level tapes for LEVELDIR\n"
@@ -7643,7 +9090,6 @@ static void print_usage(void)
        "  \"convert LEVELDIR [NR]\"          convert levels in LEVELDIR\n"
        "  \"create sketch images DIRECTORY\" write BMP images to DIRECTORY\n"
        "  \"create collect image DIRECTORY\" write BMP image to DIRECTORY\n"
-       "  \"create CE image DIRECTORY\"      write BMP image to DIRECTORY\n"
        "\n",
        program.command_basename);
 }
@@ -7700,33 +9146,13 @@ static void InitProgramConfig(char *command_filename)
   char *program_title = PROGRAM_TITLE_STRING;
   char *program_icon_file = PROGRAM_ICON_FILENAME;
   char *program_version = getProgramRealVersionString();
+  char *program_basename = getBaseNameNoSuffix(command_filename);
   char *config_filename = getProgramConfigFilename(command_filename);
-  char *userdata_basename = getBaseNameNoSuffix(command_filename);
   char *userdata_subdir;
-#if defined(PLATFORM_UNIX)
-  char *userdata_subdir_unix;
-#endif
 
   // read default program config, if existing
   if (fileExists(config_filename))
-  {
-    // if program config file exists, derive Unix user data directory from it
-    // (but only if the program config file is not generic "setup.conf" file)
-    if (!strEqual(getBaseNamePtr(config_filename), SETUP_FILENAME))
-    {
-      userdata_basename = getBaseName(config_filename);
-
-      if (strSuffix(userdata_basename, ".conf"))
-       userdata_basename[strlen(userdata_basename) - 5] = '\0';
-    }
-
     LoadSetupFromFilename(config_filename);
-  }
-
-#if defined(PLATFORM_UNIX)
-  // set user data directory for Linux/Unix (but not Mac OS X)
-  userdata_subdir_unix = getStringCat2(".", userdata_basename);
-#endif
 
   // set program title from potentially redefined program title
   if (setup.internal.program_title != NULL &&
@@ -7743,10 +9169,10 @@ static void InitProgramConfig(char *command_filename)
       strlen(setup.internal.program_icon_file) > 0)
     program_icon_file = getStringCopy(setup.internal.program_icon_file);
 
-#if defined(PLATFORM_WIN32) || defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_MAC) || defined(PLATFORM_EMSCRIPTEN)
   userdata_subdir = program_title;
 #elif defined(PLATFORM_UNIX)
-  userdata_subdir = userdata_subdir_unix;
+  userdata_subdir = getStringCat2(".", program_basename);
 #else
   userdata_subdir = USERDATA_DIRECTORY_OTHER;
 #endif
@@ -7762,7 +9188,7 @@ static void InitProgramConfig(char *command_filename)
   InitProgramInfo(command_filename,
                  config_filename,
                  userdata_subdir,
-                 program_title,
+                 program_basename,
                  program_title,
                  program_icon_file,
                  COOKIE_PREFIX,
index 1b3498875fe6221c68aa2173adf08dafb29c470f..309229ee71c2fdce7670c5e19f65792c4ae6e009 100644 (file)
 #include <fcntl.h>
 
 #include "libgame/libgame.h"
+
+#include "game_bd/game_bd.h"
 #include "game_em/game_em.h"
 #include "game_sp/game_sp.h"
 #include "game_mm/game_mm.h"
-#include "engines.h"
 
 #include "conf_gfx.h"  // include auto-generated data structure definitions
 #include "conf_snd.h"  // include auto-generated data structure definitions
 
 // values for pre-defined properties
 // (from here on, values can be changed by inserting new values)
-#define EP_PLAYER                      32
-#define EP_CAN_PASS_MAGIC_WALL         33
-#define EP_CAN_PASS_DC_MAGIC_WALL      34
-#define EP_SWITCHABLE                  35
-#define EP_BD_ELEMENT                  36
-#define EP_SP_ELEMENT                  37
-#define EP_SB_ELEMENT                  38
-#define EP_GEM                         39
-#define EP_FOOD_DARK_YAMYAM            40
-#define EP_FOOD_PENGUIN                        41
-#define EP_FOOD_PIG                    42
-#define EP_HISTORIC_WALL               43
-#define EP_HISTORIC_SOLID              44
-#define EP_CLASSIC_ENEMY               45
-#define EP_BELT                                46
-#define EP_BELT_ACTIVE                 47
-#define EP_BELT_SWITCH                 48
-#define EP_TUBE                                49
-#define EP_ACID_POOL                   50
-#define EP_KEYGATE                     51
-#define EP_AMOEBOID                    52
-#define EP_AMOEBALIVE                  53
-#define EP_HAS_EDITOR_CONTENT          54
-#define EP_CAN_TURN_EACH_MOVE          55
-#define EP_CAN_GROW                    56
-#define EP_ACTIVE_BOMB                 57
-#define EP_INACTIVE                    58
+#define EP_EMPTY_SPACE                 32
+#define EP_PLAYER                      33
+#define EP_CAN_PASS_MAGIC_WALL         34
+#define EP_CAN_PASS_DC_MAGIC_WALL      35
+#define EP_SWITCHABLE                  36
+#define EP_BD_ELEMENT                  37
+#define EP_SP_ELEMENT                  38
+#define EP_SB_ELEMENT                  39
+#define EP_GEM                         40
+#define EP_FOOD_DARK_YAMYAM            41
+#define EP_FOOD_PENGUIN                        42
+#define EP_FOOD_PIG                    43
+#define EP_HISTORIC_WALL               44
+#define EP_HISTORIC_SOLID              45
+#define EP_CLASSIC_ENEMY               46
+#define EP_BELT                                47
+#define EP_BELT_ACTIVE                 48
+#define EP_BELT_SWITCH                 49
+#define EP_TUBE                                50
+#define EP_ACID_POOL                   51
+#define EP_KEYGATE                     52
+#define EP_AMOEBOID                    53
+#define EP_AMOEBALIVE                  54
+#define EP_HAS_EDITOR_CONTENT          55
+#define EP_CAN_TURN_EACH_MOVE          56
+#define EP_CAN_GROW                    57
+#define EP_ACTIVE_BOMB                 58
+#define EP_INACTIVE                    59
 
 // values for special configurable properties (depending on level settings)
-#define EP_EM_SLIPPERY_WALL            59
+#define EP_EM_SLIPPERY_WALL            60
 
 // values for special graphics properties (no effect on game engine)
-#define EP_GFX_CRUMBLED                        60
+#define EP_GFX_CRUMBLED                        61
 
 // values for derived properties (determined from properties above)
-#define EP_ACCESSIBLE_OVER             61
-#define EP_ACCESSIBLE_INSIDE           62
-#define EP_ACCESSIBLE_UNDER            63
-#define EP_WALKABLE                    64
-#define EP_PASSABLE                    65
-#define EP_ACCESSIBLE                  66
-#define EP_COLLECTIBLE                 67
-#define EP_SNAPPABLE                   68
-#define EP_WALL                                69
-#define EP_SOLID_FOR_PUSHING           70
-#define EP_DRAGONFIRE_PROOF            71
-#define EP_EXPLOSION_PROOF             72
-#define EP_CAN_SMASH                   73
-#define EP_EXPLODES_3X3_OLD            74
-#define EP_CAN_EXPLODE_BY_FIRE         75
-#define EP_CAN_EXPLODE_SMASHED         76
-#define EP_CAN_EXPLODE_IMPACT          77
-#define EP_SP_PORT                     78
-#define EP_CAN_EXPLODE_BY_DRAGONFIRE   79
-#define EP_CAN_EXPLODE_BY_EXPLOSION    80
-#define EP_COULD_MOVE_INTO_ACID                81
-#define EP_MAYBE_DONT_COLLIDE_WITH     82
-#define EP_CAN_BE_CLONED_BY_ANDROID    83
+#define EP_ACCESSIBLE_OVER             62
+#define EP_ACCESSIBLE_INSIDE           63
+#define EP_ACCESSIBLE_UNDER            64
+#define EP_WALKABLE                    65
+#define EP_PASSABLE                    66
+#define EP_ACCESSIBLE                  67
+#define EP_COLLECTIBLE                 68
+#define EP_SNAPPABLE                   69
+#define EP_WALL                                70
+#define EP_SOLID_FOR_PUSHING           71
+#define EP_DRAGONFIRE_PROOF            72
+#define EP_EXPLOSION_PROOF             73
+#define EP_CAN_SMASH                   74
+#define EP_EXPLODES_3X3_OLD            75
+#define EP_CAN_EXPLODE_BY_FIRE         76
+#define EP_CAN_EXPLODE_SMASHED         77
+#define EP_CAN_EXPLODE_IMPACT          78
+#define EP_SP_PORT                     79
+#define EP_CAN_EXPLODE_BY_DRAGONFIRE   80
+#define EP_CAN_EXPLODE_BY_EXPLOSION    81
+#define EP_COULD_MOVE_INTO_ACID                82
+#define EP_MAYBE_DONT_COLLIDE_WITH     83
+#define EP_CAN_BE_CLONED_BY_ANDROID    84
 
 // values for internal purpose only (level editor)
-#define EP_WALK_TO_OBJECT              84
-#define EP_DEADLY                      85
-#define EP_EDITOR_CASCADE              86
-#define EP_EDITOR_CASCADE_ACTIVE       87
-#define EP_EDITOR_CASCADE_INACTIVE     88
+#define EP_WALK_TO_OBJECT              85
+#define EP_DEADLY                      86
+#define EP_EDITOR_CASCADE              87
+#define EP_EDITOR_CASCADE_ACTIVE       88
+#define EP_EDITOR_CASCADE_INACTIVE     89
 
 // values for internal purpose only (game engine)
-#define EP_HAS_ACTION                  89
-#define EP_CAN_CHANGE_OR_HAS_ACTION    90
+#define EP_HAS_ACTION                  90
+#define EP_CAN_CHANGE_OR_HAS_ACTION    91
 
 // values for internal purpose only (other)
-#define EP_OBSOLETE                    91
+#define EP_OBSOLETE                    92
 
-#define NUM_ELEMENT_PROPERTIES         92
+#define NUM_ELEMENT_PROPERTIES         93
 
 #define NUM_EP_BITFIELDS               ((NUM_ELEMENT_PROPERTIES + 31) / 32)
 #define EP_BITFIELD_BASE_NR            0
 #define EP_BITMASK_BASE_DEFAULT                (1 << EP_CAN_MOVE_INTO_ACID)
 #define EP_BITMASK_DEFAULT             0
 
-#define PROPERTY_BIT(p)                        (1 << ((p) % 32))
-#define PROPERTY_VAR(e,p)              (element_info[e].properties[(p) / 32])
-#define HAS_PROPERTY(e,p)      ((PROPERTY_VAR(e, p) & PROPERTY_BIT(p)) != 0)
-#define SET_PROPERTY(e,p,v)    ((v) ?                                     \
-                                (PROPERTY_VAR(e,p) |=  PROPERTY_BIT(p)) : \
-                                (PROPERTY_VAR(e,p) &= ~PROPERTY_BIT(p)))
+#define PROPERTY_BIT(p)                        (1u << ((p) % 32))
+#define PROPERTY_VAR(e, p)             (element_info[e].properties[(p) / 32])
+#define HAS_PROPERTY(e, p)             ((PROPERTY_VAR(e, p) & PROPERTY_BIT(p)) != 0)
+#define SET_PROPERTY(e, p, v)          ((v) ?                                     \
+                                        (PROPERTY_VAR(e,p) |=  PROPERTY_BIT(p)) : \
+                                        (PROPERTY_VAR(e,p) &= ~PROPERTY_BIT(p)))
 
 
 // values for change events for custom elements (stored in level file)
 #define CE_PRESSED_BY_MOUSE            45
 #define CE_MOUSE_CLICKED_ON_X          46
 #define CE_MOUSE_PRESSED_ON_X          47
+#define CE_NEXT_TO_PLAYER              48
+#define CE_NEXT_TO_X                   49
+#define CE_PLAYER_NEXT_TO_X            50
 
-#define NUM_CHANGE_EVENTS              48
+#define NUM_CHANGE_EVENTS              51
 
 #define NUM_CE_BITFIELDS               ((NUM_CHANGE_EVENTS + 31) / 32)
 
 #define CH_EVENT_BITFIELD_NR(e)                (e / 32)
 #define CH_EVENT_BIT(e)                        (1 << ((e) % 32))
 
-#define CH_EVENT_VAR(e,c)              (element_info[e].change->has_event[c])
-#define CH_ANY_EVENT_VAR(e,c)          (element_info[e].has_change_event[c])
+#define CH_EVENT_VAR(e, c)             (element_info[e].change->has_event[c])
+#define CH_ANY_EVENT_VAR(e, c)         (element_info[e].has_change_event[c])
 
-#define PAGE_HAS_CHANGE_EVENT(p,c)     ((p)->has_event[c])
-#define HAS_CHANGE_EVENT(e,c)          (IS_CUSTOM_ELEMENT(e) &&        \
-                                        CH_EVENT_VAR(e,c))
-#define HAS_ANY_CHANGE_EVENT(e,c)      (IS_CUSTOM_ELEMENT(e) &&        \
-                                        CH_ANY_EVENT_VAR(e,c))
+#define PAGE_HAS_CHANGE_EVENT(p, c)    ((p)->has_event[c])
+#define HAS_CHANGE_EVENT(e, c)         (IS_CUSTOM_ELEMENT(e) && CH_EVENT_VAR(e, c))
+#define HAS_ANY_CHANGE_EVENT(e, c)     (IS_CUSTOM_ELEMENT(e) && CH_ANY_EVENT_VAR(e, c))
 
-#define SET_CHANGE_EVENT(e,c,v)                (IS_CUSTOM_ELEMENT(e) ?         \
-                                        CH_EVENT_VAR(e,c) = (v) : 0)
-#define SET_ANY_CHANGE_EVENT(e,c,v)    (IS_CUSTOM_ELEMENT(e) ?         \
-                                        CH_ANY_EVENT_VAR(e,c) = (v) : 0)
+#define SET_CHANGE_EVENT(e, c, v)      (IS_CUSTOM_ELEMENT(e) ? CH_EVENT_VAR(e, c) = (v) : 0)
+#define SET_ANY_CHANGE_EVENT(e, c, v)  (IS_CUSTOM_ELEMENT(e) ? CH_ANY_EVENT_VAR(e, c) = (v) : 0)
 
 // values for player bitmasks
 #define PLAYER_BITS_NONE               0
 #define CH_SIDE_TOP_BOTTOM             MV_VERTICAL
 #define CH_SIDE_ANY                    MV_ANY_DIRECTION
 
-#define CH_SIDE_FROM_BUTTON(b) ((b) == MB_LEFTBUTTON   ? CH_SIDE_LEFT :       \
-                                (b) == MB_RIGHTBUTTON  ? CH_SIDE_RIGHT :      \
-                                (b) == MB_MIDDLEBUTTON ? CH_SIDE_TOP_BOTTOM : \
-                                CH_SIDE_NONE)
+#define CH_SIDE_FROM_BUTTON(b)         ((b) == MB_LEFTBUTTON   ? CH_SIDE_LEFT :       \
+                                        (b) == MB_RIGHTBUTTON  ? CH_SIDE_RIGHT :      \
+                                        (b) == MB_MIDDLEBUTTON ? CH_SIDE_TOP_BOTTOM : \
+                                        CH_SIDE_NONE)
 
 // values for change player for custom elements
 #define CH_PLAYER_NONE                 PLAYER_BITS_NONE
 #define EXPLODES_CROSS                 2
 
 // macros for configurable properties
-#define IS_DIGGABLE(e)         HAS_PROPERTY(e, EP_DIGGABLE)
-#define IS_COLLECTIBLE_ONLY(e) HAS_PROPERTY(e, EP_COLLECTIBLE_ONLY)
-#define DONT_RUN_INTO(e)       HAS_PROPERTY(e, EP_DONT_RUN_INTO)
-#define DONT_COLLIDE_WITH(e)   HAS_PROPERTY(e, EP_DONT_COLLIDE_WITH)
-#define DONT_TOUCH(e)          HAS_PROPERTY(e, EP_DONT_TOUCH)
-#define IS_INDESTRUCTIBLE(e)   HAS_PROPERTY(e, EP_INDESTRUCTIBLE)
-#define IS_SLIPPERY(e)         HAS_PROPERTY(e, EP_SLIPPERY)
-#define CAN_CHANGE(e)          HAS_PROPERTY(e, EP_CAN_CHANGE)
-#define CAN_MOVE(e)            HAS_PROPERTY(e, EP_CAN_MOVE)
-#define CAN_FALL(e)            HAS_PROPERTY(e, EP_CAN_FALL)
-#define CAN_SMASH_PLAYER(e)    HAS_PROPERTY(e, EP_CAN_SMASH_PLAYER)
-#define CAN_SMASH_ENEMIES(e)   HAS_PROPERTY(e, EP_CAN_SMASH_ENEMIES)
-#define CAN_SMASH_EVERYTHING(e)        HAS_PROPERTY(e, EP_CAN_SMASH_EVERYTHING)
-#define EXPLODES_BY_FIRE(e)    HAS_PROPERTY(e, EP_EXPLODES_BY_FIRE)
-#define EXPLODES_SMASHED(e)    HAS_PROPERTY(e, EP_EXPLODES_SMASHED)
-#define EXPLODES_IMPACT(e)     HAS_PROPERTY(e, EP_EXPLODES_IMPACT)
-#define IS_WALKABLE_OVER(e)    HAS_PROPERTY(e, EP_WALKABLE_OVER)
-#define IS_WALKABLE_INSIDE(e)  HAS_PROPERTY(e, EP_WALKABLE_INSIDE)
-#define IS_WALKABLE_UNDER(e)   HAS_PROPERTY(e, EP_WALKABLE_UNDER)
-#define IS_PASSABLE_OVER(e)    HAS_PROPERTY(e, EP_PASSABLE_OVER)
-#define IS_PASSABLE_INSIDE(e)  HAS_PROPERTY(e, EP_PASSABLE_INSIDE)
-#define IS_PASSABLE_UNDER(e)   HAS_PROPERTY(e, EP_PASSABLE_UNDER)
-#define IS_DROPPABLE(e)                HAS_PROPERTY(e, EP_DROPPABLE)
-#define EXPLODES_1X1_OLD(e)    HAS_PROPERTY(e, EP_EXPLODES_1X1_OLD)
-#define IS_PUSHABLE(e)         HAS_PROPERTY(e, EP_PUSHABLE)
-#define EXPLODES_CROSS_OLD(e)  HAS_PROPERTY(e, EP_EXPLODES_CROSS_OLD)
-#define IS_PROTECTED(e)                HAS_PROPERTY(e, EP_PROTECTED)
-#define CAN_MOVE_INTO_ACID(e)  HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID)
-#define IS_THROWABLE(e)                HAS_PROPERTY(e, EP_THROWABLE)
-#define CAN_EXPLODE(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE)
-#define IS_GRAVITY_REACHABLE(e)        HAS_PROPERTY(e, EP_GRAVITY_REACHABLE)
-#define DONT_GET_HIT_BY(e)     HAS_PROPERTY(e, EP_DONT_GET_HIT_BY)
+#define IS_DIGGABLE(e)                 HAS_PROPERTY(e, EP_DIGGABLE)
+#define IS_COLLECTIBLE_ONLY(e)         HAS_PROPERTY(e, EP_COLLECTIBLE_ONLY)
+#define DONT_RUN_INTO(e)               HAS_PROPERTY(e, EP_DONT_RUN_INTO)
+#define DONT_COLLIDE_WITH(e)           HAS_PROPERTY(e, EP_DONT_COLLIDE_WITH)
+#define DONT_TOUCH(e)                  HAS_PROPERTY(e, EP_DONT_TOUCH)
+#define IS_INDESTRUCTIBLE(e)           HAS_PROPERTY(e, EP_INDESTRUCTIBLE)
+#define IS_SLIPPERY(e)                 HAS_PROPERTY(e, EP_SLIPPERY)
+#define CAN_CHANGE(e)                  HAS_PROPERTY(e, EP_CAN_CHANGE)
+#define CAN_MOVE(e)                    HAS_PROPERTY(e, EP_CAN_MOVE)
+#define CAN_FALL(e)                    HAS_PROPERTY(e, EP_CAN_FALL)
+#define CAN_SMASH_PLAYER(e)            HAS_PROPERTY(e, EP_CAN_SMASH_PLAYER)
+#define CAN_SMASH_ENEMIES(e)           HAS_PROPERTY(e, EP_CAN_SMASH_ENEMIES)
+#define CAN_SMASH_EVERYTHING(e)                HAS_PROPERTY(e, EP_CAN_SMASH_EVERYTHING)
+#define EXPLODES_BY_FIRE(e)            HAS_PROPERTY(e, EP_EXPLODES_BY_FIRE)
+#define EXPLODES_SMASHED(e)            HAS_PROPERTY(e, EP_EXPLODES_SMASHED)
+#define EXPLODES_IMPACT(e)             HAS_PROPERTY(e, EP_EXPLODES_IMPACT)
+#define IS_WALKABLE_OVER(e)            HAS_PROPERTY(e, EP_WALKABLE_OVER)
+#define IS_WALKABLE_INSIDE(e)          HAS_PROPERTY(e, EP_WALKABLE_INSIDE)
+#define IS_WALKABLE_UNDER(e)           HAS_PROPERTY(e, EP_WALKABLE_UNDER)
+#define IS_PASSABLE_OVER(e)            HAS_PROPERTY(e, EP_PASSABLE_OVER)
+#define IS_PASSABLE_INSIDE(e)          HAS_PROPERTY(e, EP_PASSABLE_INSIDE)
+#define IS_PASSABLE_UNDER(e)           HAS_PROPERTY(e, EP_PASSABLE_UNDER)
+#define IS_DROPPABLE(e)                        HAS_PROPERTY(e, EP_DROPPABLE)
+#define EXPLODES_1X1_OLD(e)            HAS_PROPERTY(e, EP_EXPLODES_1X1_OLD)
+#define IS_PUSHABLE(e)                 HAS_PROPERTY(e, EP_PUSHABLE)
+#define EXPLODES_CROSS_OLD(e)          HAS_PROPERTY(e, EP_EXPLODES_CROSS_OLD)
+#define IS_PROTECTED(e)                        HAS_PROPERTY(e, EP_PROTECTED)
+#define CAN_MOVE_INTO_ACID(e)          HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID)
+#define IS_THROWABLE(e)                        HAS_PROPERTY(e, EP_THROWABLE)
+#define CAN_EXPLODE(e)                 HAS_PROPERTY(e, EP_CAN_EXPLODE)
+#define IS_GRAVITY_REACHABLE(e)                HAS_PROPERTY(e, EP_GRAVITY_REACHABLE)
+#define DONT_GET_HIT_BY(e)             HAS_PROPERTY(e, EP_DONT_GET_HIT_BY)
 
 // macros for special configurable properties
-#define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL)
+#define IS_EM_SLIPPERY_WALL(e)         HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL)
 
 // macros for special graphics properties
-#define GFX_CRUMBLED(e)                HAS_PROPERTY(GFX_ELEMENT(e), EP_GFX_CRUMBLED)
+#define GFX_CRUMBLED(e)                        HAS_PROPERTY(GFX_ELEMENT(e), EP_GFX_CRUMBLED)
 
 // macros for pre-defined properties
-#define IS_PLAYER_ELEMENT(e)   HAS_PROPERTY(e, EP_PLAYER)
-#define CAN_PASS_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_MAGIC_WALL)
-#define CAN_PASS_DC_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_DC_MAGIC_WALL)
-#define IS_SWITCHABLE(e)       HAS_PROPERTY(e, EP_SWITCHABLE)
-#define IS_BD_ELEMENT(e)       HAS_PROPERTY(e, EP_BD_ELEMENT)
-#define IS_SP_ELEMENT(e)       HAS_PROPERTY(e, EP_SP_ELEMENT)
-#define IS_SB_ELEMENT(e)       HAS_PROPERTY(e, EP_SB_ELEMENT)
-#define IS_GEM(e)              HAS_PROPERTY(e, EP_GEM)
-#define IS_FOOD_DARK_YAMYAM(e) HAS_PROPERTY(e, EP_FOOD_DARK_YAMYAM)
-#define IS_FOOD_PENGUIN(e)     HAS_PROPERTY(e, EP_FOOD_PENGUIN)
-#define IS_FOOD_PIG(e)         HAS_PROPERTY(e, EP_FOOD_PIG)
-#define IS_HISTORIC_WALL(e)    HAS_PROPERTY(e, EP_HISTORIC_WALL)
-#define IS_HISTORIC_SOLID(e)   HAS_PROPERTY(e, EP_HISTORIC_SOLID)
-#define IS_CLASSIC_ENEMY(e)    HAS_PROPERTY(e, EP_CLASSIC_ENEMY)
-#define IS_BELT(e)             HAS_PROPERTY(e, EP_BELT)
-#define IS_BELT_ACTIVE(e)      HAS_PROPERTY(e, EP_BELT_ACTIVE)
-#define IS_BELT_SWITCH(e)      HAS_PROPERTY(e, EP_BELT_SWITCH)
-#define IS_TUBE(e)             HAS_PROPERTY(e, EP_TUBE)
-#define IS_ACID_POOL(e)                HAS_PROPERTY(e, EP_ACID_POOL)
-#define IS_KEYGATE(e)          HAS_PROPERTY(e, EP_KEYGATE)
-#define IS_AMOEBOID(e)         HAS_PROPERTY(e, EP_AMOEBOID)
-#define IS_AMOEBALIVE(e)       HAS_PROPERTY(e, EP_AMOEBALIVE)
-#define HAS_EDITOR_CONTENT(e)  HAS_PROPERTY(e, EP_HAS_EDITOR_CONTENT)
-#define CAN_TURN_EACH_MOVE(e)  HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE)
-#define CAN_GROW(e)            HAS_PROPERTY(e, EP_CAN_GROW)
-#define IS_ACTIVE_BOMB(e)      HAS_PROPERTY(e, EP_ACTIVE_BOMB)
-#define IS_INACTIVE(e)         HAS_PROPERTY(e, EP_INACTIVE)
+#define IS_EMPTY_SPACE(e)              HAS_PROPERTY(e, EP_EMPTY_SPACE)
+#define IS_PLAYER_ELEMENT(e)           HAS_PROPERTY(e, EP_PLAYER)
+#define CAN_PASS_MAGIC_WALL(e)         HAS_PROPERTY(e, EP_CAN_PASS_MAGIC_WALL)
+#define CAN_PASS_DC_MAGIC_WALL(e)      HAS_PROPERTY(e, EP_CAN_PASS_DC_MAGIC_WALL)
+#define IS_SWITCHABLE(e)               HAS_PROPERTY(e, EP_SWITCHABLE)
+#define IS_BD_ELEMENT(e)               HAS_PROPERTY(e, EP_BD_ELEMENT)
+#define IS_SP_ELEMENT(e)               HAS_PROPERTY(e, EP_SP_ELEMENT)
+#define IS_SB_ELEMENT(e)               HAS_PROPERTY(e, EP_SB_ELEMENT)
+#define IS_GEM(e)                      HAS_PROPERTY(e, EP_GEM)
+#define IS_FOOD_DARK_YAMYAM(e)         HAS_PROPERTY(e, EP_FOOD_DARK_YAMYAM)
+#define IS_FOOD_PENGUIN(e)             HAS_PROPERTY(e, EP_FOOD_PENGUIN)
+#define IS_FOOD_PIG(e)                 HAS_PROPERTY(e, EP_FOOD_PIG)
+#define IS_HISTORIC_WALL(e)            HAS_PROPERTY(e, EP_HISTORIC_WALL)
+#define IS_HISTORIC_SOLID(e)           HAS_PROPERTY(e, EP_HISTORIC_SOLID)
+#define IS_CLASSIC_ENEMY(e)            HAS_PROPERTY(e, EP_CLASSIC_ENEMY)
+#define IS_BELT(e)                     HAS_PROPERTY(e, EP_BELT)
+#define IS_BELT_ACTIVE(e)              HAS_PROPERTY(e, EP_BELT_ACTIVE)
+#define IS_BELT_SWITCH(e)              HAS_PROPERTY(e, EP_BELT_SWITCH)
+#define IS_TUBE(e)                     HAS_PROPERTY(e, EP_TUBE)
+#define IS_ACID_POOL(e)                        HAS_PROPERTY(e, EP_ACID_POOL)
+#define IS_KEYGATE(e)                  HAS_PROPERTY(e, EP_KEYGATE)
+#define IS_AMOEBOID(e)                 HAS_PROPERTY(e, EP_AMOEBOID)
+#define IS_AMOEBALIVE(e)               HAS_PROPERTY(e, EP_AMOEBALIVE)
+#define HAS_EDITOR_CONTENT(e)          HAS_PROPERTY(e, EP_HAS_EDITOR_CONTENT)
+#define CAN_TURN_EACH_MOVE(e)          HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE)
+#define CAN_GROW(e)                    HAS_PROPERTY(e, EP_CAN_GROW)
+#define IS_ACTIVE_BOMB(e)              HAS_PROPERTY(e, EP_ACTIVE_BOMB)
+#define IS_INACTIVE(e)                 HAS_PROPERTY(e, EP_INACTIVE)
 
 // macros for derived properties
-#define IS_ACCESSIBLE_OVER(e)  HAS_PROPERTY(e, EP_ACCESSIBLE_OVER)
-#define IS_ACCESSIBLE_INSIDE(e)        HAS_PROPERTY(e, EP_ACCESSIBLE_INSIDE)
-#define IS_ACCESSIBLE_UNDER(e) HAS_PROPERTY(e, EP_ACCESSIBLE_UNDER)
-#define IS_WALKABLE(e)         HAS_PROPERTY(e, EP_WALKABLE)
-#define IS_PASSABLE(e)         HAS_PROPERTY(e, EP_PASSABLE)
-#define IS_ACCESSIBLE(e)       HAS_PROPERTY(e, EP_ACCESSIBLE)
-#define IS_COLLECTIBLE(e)      HAS_PROPERTY(e, EP_COLLECTIBLE)
-#define IS_SNAPPABLE(e)                HAS_PROPERTY(e, EP_SNAPPABLE)
-#define IS_WALL(e)             HAS_PROPERTY(e, EP_WALL)
-#define IS_SOLID_FOR_PUSHING(e)        HAS_PROPERTY(e, EP_SOLID_FOR_PUSHING)
-#define IS_DRAGONFIRE_PROOF(e) HAS_PROPERTY(e, EP_DRAGONFIRE_PROOF)
-#define IS_EXPLOSION_PROOF(e)  HAS_PROPERTY(e, EP_EXPLOSION_PROOF)
-#define CAN_SMASH(e)           HAS_PROPERTY(e, EP_CAN_SMASH)
-#define EXPLODES_3X3_OLD(e)    HAS_PROPERTY(e, EP_EXPLODES_3X3_OLD)
-#define CAN_EXPLODE_BY_FIRE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE)
-#define CAN_EXPLODE_SMASHED(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED)
-#define CAN_EXPLODE_IMPACT(e)  HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT)
-#define IS_SP_PORT(e)          HAS_PROPERTY(e, EP_SP_PORT)
-#define CAN_EXPLODE_BY_DRAGONFIRE(e)   \
-                               HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE)
-#define CAN_EXPLODE_BY_EXPLOSION(e)    \
-                               HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION)
-#define COULD_MOVE_INTO_ACID(e)        HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID)
-#define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH)
-#define CAN_BE_CLONED_BY_ANDROID(e)    \
-                               HAS_PROPERTY(e, EP_CAN_BE_CLONED_BY_ANDROID)
-
-#define IS_EDITOR_CASCADE(e)   HAS_PROPERTY(e, EP_EDITOR_CASCADE)
-#define IS_EDITOR_CASCADE_ACTIVE(e)    \
-                               HAS_PROPERTY(e, EP_EDITOR_CASCADE_ACTIVE)
-#define IS_EDITOR_CASCADE_INACTIVE(e)  \
-                               HAS_PROPERTY(e, EP_EDITOR_CASCADE_INACTIVE)
-
-#define HAS_ACTION(e)          HAS_PROPERTY(e, EP_HAS_ACTION)
-#define CAN_CHANGE_OR_HAS_ACTION(e)    \
-                               HAS_PROPERTY(e, EP_CAN_CHANGE_OR_HAS_ACTION)
-
-#define IS_OBSOLETE(e)         HAS_PROPERTY(e, EP_OBSOLETE)
+#define IS_ACCESSIBLE_OVER(e)          HAS_PROPERTY(e, EP_ACCESSIBLE_OVER)
+#define IS_ACCESSIBLE_INSIDE(e)                HAS_PROPERTY(e, EP_ACCESSIBLE_INSIDE)
+#define IS_ACCESSIBLE_UNDER(e)         HAS_PROPERTY(e, EP_ACCESSIBLE_UNDER)
+#define IS_WALKABLE(e)                 HAS_PROPERTY(e, EP_WALKABLE)
+#define IS_PASSABLE(e)                 HAS_PROPERTY(e, EP_PASSABLE)
+#define IS_ACCESSIBLE(e)               HAS_PROPERTY(e, EP_ACCESSIBLE)
+#define IS_COLLECTIBLE(e)              HAS_PROPERTY(e, EP_COLLECTIBLE)
+#define IS_SNAPPABLE(e)                        HAS_PROPERTY(e, EP_SNAPPABLE)
+#define IS_WALL(e)                     HAS_PROPERTY(e, EP_WALL)
+#define IS_SOLID_FOR_PUSHING(e)                HAS_PROPERTY(e, EP_SOLID_FOR_PUSHING)
+#define IS_DRAGONFIRE_PROOF(e)         HAS_PROPERTY(e, EP_DRAGONFIRE_PROOF)
+#define IS_EXPLOSION_PROOF(e)          HAS_PROPERTY(e, EP_EXPLOSION_PROOF)
+#define CAN_SMASH(e)                   HAS_PROPERTY(e, EP_CAN_SMASH)
+#define EXPLODES_3X3_OLD(e)            HAS_PROPERTY(e, EP_EXPLODES_3X3_OLD)
+#define CAN_EXPLODE_BY_FIRE(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE)
+#define CAN_EXPLODE_SMASHED(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED)
+#define CAN_EXPLODE_IMPACT(e)          HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT)
+#define IS_SP_PORT(e)                  HAS_PROPERTY(e, EP_SP_PORT)
+#define CAN_EXPLODE_BY_DRAGONFIRE(e)   HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE)
+#define CAN_EXPLODE_BY_EXPLOSION(e)    HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION)
+#define COULD_MOVE_INTO_ACID(e)                HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID)
+#define MAYBE_DONT_COLLIDE_WITH(e)     HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH)
+#define CAN_BE_CLONED_BY_ANDROID(e)    HAS_PROPERTY(e, EP_CAN_BE_CLONED_BY_ANDROID)
+
+#define IS_EDITOR_CASCADE(e)           HAS_PROPERTY(e, EP_EDITOR_CASCADE)
+#define IS_EDITOR_CASCADE_ACTIVE(e)    HAS_PROPERTY(e, EP_EDITOR_CASCADE_ACTIVE)
+#define IS_EDITOR_CASCADE_INACTIVE(e)  HAS_PROPERTY(e, EP_EDITOR_CASCADE_INACTIVE)
+
+#define HAS_ACTION(e)                  HAS_PROPERTY(e, EP_HAS_ACTION)
+#define CAN_CHANGE_OR_HAS_ACTION(e)    HAS_PROPERTY(e, EP_CAN_CHANGE_OR_HAS_ACTION)
+
+#define IS_OBSOLETE(e)                 HAS_PROPERTY(e, EP_OBSOLETE)
+
+#define IS_EMPTY(e)                    IS_EMPTY_SPACE(e)
+#define IS_EMPTY_ELEMENT(e)            IS_EMPTY_SPACE(e)
 
 // special macros used in game engine
-#define IS_FILE_ELEMENT(e)     ((e) >= 0 &&                            \
-                                (e) <= NUM_FILE_ELEMENTS)
-
-#define IS_DRAWABLE_ELEMENT(e) ((e) >= 0 &&                            \
-                                (e) <= NUM_DRAWABLE_ELEMENTS)
-
-#define IS_RUNTIME_ELEMENT(e)  ((e) >= 0 &&                            \
-                                (e) <= NUM_RUNTIME_ELEMENTS)
-
-#define IS_VALID_ELEMENT(e)    ((e) >= 0 &&                            \
-                                (e) <= MAX_NUM_ELEMENTS)
-
-#define IS_CUSTOM_ELEMENT(e)   ((e) >= EL_CUSTOM_START &&              \
-                                (e) <= EL_CUSTOM_END)
-
-#define IS_GROUP_ELEMENT(e)    ((e) >= EL_GROUP_START &&               \
-                                (e) <= EL_GROUP_END)
-
-#define IS_CLIPBOARD_ELEMENT(e)        ((e) >= EL_INTERNAL_CLIPBOARD_START &&  \
-                                (e) <= EL_INTERNAL_CLIPBOARD_END)
-
-#define IS_INTERNAL_ELEMENT(e) ((e) >= EL_INTERNAL_START &&            \
-                                (e) <= EL_INTERNAL_END)
-
-#define IS_MM_ELEMENT(e)       ((e) >= EL_MM_START &&                  \
-                                (e) <= EL_MM_END)
-
-#define IS_DF_ELEMENT(e)       ((e) >= EL_DF_START &&                  \
-                                (e) <= EL_DF_END)
-
-#define IS_MM_MCDUFFIN(e)      ((e) >= EL_MM_MCDUFFIN_START &&         \
-                                (e) <= EL_MM_MCDUFFIN_END)
-
-#define IS_DF_LASER(e)         ((e) >= EL_DF_LASER_START &&            \
-                                (e) <= EL_DF_LASER_END)
-
-#define IS_MM_WALL(e)          (((e) >= EL_MM_WALL_START &&            \
-                                 (e) <= EL_MM_WALL_END) ||             \
-                                ((e) >= EL_DF_WALL_START &&            \
-                                 (e) <= EL_DF_WALL_END))
-
-#define IS_DF_WALL(e)          ((e) >= EL_DF_WALL_START &&             \
-                                (e) <= EL_DF_WALL_END)
-
-#define IS_MM_WALL_EDITOR(e)   ((e) == EL_MM_STEEL_WALL ||             \
-                                (e) == EL_MM_WOODEN_WALL ||            \
-                                (e) == EL_MM_ICE_WALL ||               \
-                                (e) == EL_MM_AMOEBA_WALL ||            \
-                                (e) == EL_DF_STEEL_WALL ||             \
-                                (e) == EL_DF_WOODEN_WALL)
-
-#define IS_ENVELOPE(e)         ((e) >= EL_ENVELOPE_1 &&                \
-                                (e) <= EL_ENVELOPE_4)
-
-#define IS_BALLOON_ELEMENT(e)  ((e) == EL_BALLOON ||                   \
-                                (e) == EL_BALLOON_SWITCH_LEFT ||       \
-                                (e) == EL_BALLOON_SWITCH_RIGHT ||      \
-                                (e) == EL_BALLOON_SWITCH_UP ||         \
-                                (e) == EL_BALLOON_SWITCH_DOWN ||       \
-                                (e) == EL_BALLOON_SWITCH_ANY ||        \
-                                (e) == EL_BALLOON_SWITCH_NONE)
-
-#define IS_RND_KEY(e)          ((e) >= EL_KEY_1 &&                     \
-                                (e) <= EL_KEY_4)
-#define IS_EM_KEY(e)           ((e) >= EL_EM_KEY_1 &&                  \
-                                (e) <= EL_EM_KEY_4)
-#define IS_EMC_KEY(e)          ((e) >= EL_EMC_KEY_5 &&                 \
-                                (e) <= EL_EMC_KEY_8)
-#define IS_KEY(e)              (IS_RND_KEY(e) ||                       \
-                                IS_EM_KEY(e) ||                        \
-                                IS_EMC_KEY(e))
-#define RND_KEY_NR(e)          ((e) - EL_KEY_1)
-#define EM_KEY_NR(e)           ((e) - EL_EM_KEY_1)
-#define EMC_KEY_NR(e)          ((e) - EL_EMC_KEY_5 + 4)
-#define KEY_NR(e)              (IS_RND_KEY(e) ? RND_KEY_NR(e) :        \
-                                IS_EM_KEY(e)  ? EM_KEY_NR(e)  :        \
-                                IS_EMC_KEY(e) ? EMC_KEY_NR(e) : 0)
-
-#define IS_RND_GATE(e)         ((e) >= EL_GATE_1 &&                    \
-                                (e) <= EL_GATE_4)
-#define IS_EM_GATE(e)          ((e) >= EL_EM_GATE_1 &&                 \
-                                (e) <= EL_EM_GATE_4)
-#define IS_EMC_GATE(e)         ((e) >= EL_EMC_GATE_5 &&                \
-                                (e) <= EL_EMC_GATE_8)
-#define IS_DC_GATE(e)          ((e) == EL_DC_GATE_WHITE)
-#define IS_GATE(e)             (IS_RND_GATE(e) ||                      \
-                                IS_EM_GATE(e) ||                       \
-                                IS_EMC_GATE(e) ||                      \
-                                IS_DC_GATE(e))
-#define RND_GATE_NR(e)         ((e) - EL_GATE_1)
-#define EM_GATE_NR(e)          ((e) - EL_EM_GATE_1)
-#define EMC_GATE_NR(e)         ((e) - EL_EMC_GATE_5 + 4)
-#define GATE_NR(e)             (IS_RND_GATE(e) ? RND_GATE_NR(e) :      \
-                                IS_EM_GATE(e) ?  EM_GATE_NR(e) :       \
-                                IS_EMC_GATE(e) ? EMC_GATE_NR(e) : 0)
-
-#define IS_RND_GATE_GRAY(e)    ((e) >= EL_GATE_1_GRAY &&               \
-                                (e) <= EL_GATE_4_GRAY)
-#define IS_RND_GATE_GRAY_ACTIVE(e) ((e) >= EL_GATE_1_GRAY_ACTIVE &&    \
-                                (e) <= EL_GATE_4_GRAY_ACTIVE)
-#define IS_EM_GATE_GRAY(e)     ((e) >= EL_EM_GATE_1_GRAY &&            \
-                                (e) <= EL_EM_GATE_4_GRAY)
-#define IS_EM_GATE_GRAY_ACTIVE(e) ((e) >= EL_EM_GATE_1_GRAY_ACTIVE &&  \
-                                (e) <= EL_EM_GATE_4_GRAY_ACTIVE)
-#define IS_EMC_GATE_GRAY(e)    ((e) >= EL_EMC_GATE_5_GRAY &&           \
-                                (e) <= EL_EMC_GATE_8_GRAY)
-#define IS_EMC_GATE_GRAY_ACTIVE(e) ((e) >= EL_EMC_GATE_5_GRAY_ACTIVE &&        \
-                                (e) <= EL_EMC_GATE_8_GRAY_ACTIVE)
-#define IS_DC_GATE_GRAY(e)     ((e) == EL_DC_GATE_WHITE_GRAY)
-#define IS_DC_GATE_GRAY_ACTIVE(e) ((e) == EL_DC_GATE_WHITE_GRAY_ACTIVE)
-
-#define IS_GATE_GRAY(e)                (IS_RND_GATE_GRAY(e) ||                 \
-                                IS_EM_GATE_GRAY(e) ||                  \
-                                IS_EMC_GATE_GRAY(e) ||                 \
-                                IS_DC_GATE_GRAY(e))
-#define IS_GATE_GRAY_ACTIVE(e) (IS_RND_GATE_GRAY_ACTIVE(e) ||          \
-                                IS_EM_GATE_GRAY_ACTIVE(e) ||           \
-                                IS_EMC_GATE_GRAY_ACTIVE(e) ||          \
-                                IS_DC_GATE_GRAY_ACTIVE(e))
-#define RND_GATE_GRAY_NR(e)    ((e) - EL_GATE_1_GRAY)
-#define RND_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_GATE_1_GRAY_ACTIVE)
-#define EM_GATE_GRAY_NR(e)     ((e) - EL_EM_GATE_1_GRAY)
-#define EM_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EM_GATE_1_GRAY_ACTIVE)
-#define EMC_GATE_GRAY_NR(e)    ((e) - EL_EMC_GATE_5_GRAY + 4)
-#define EMC_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EMC_GATE_5_GRAY_ACTIVE + 4)
-#define GATE_GRAY_NR(e)                (IS_RND_GATE_GRAY(e) ? RND_GATE_GRAY_NR(e) :  \
-                                IS_EM_GATE_GRAY(e) ?  EM_GATE_GRAY_NR(e) :   \
-                                IS_EMC_GATE_GRAY(e) ? EMC_GATE_GRAY_NR(e) : 0)
-
-#define IS_ACID_POOL_OR_ACID(e)        (IS_ACID_POOL(e) || (e) == EL_ACID)
-
-#define IS_EMC_PILLAR(e)       ((e) >= EL_EMC_WALL_1 &&                \
-                                (e) <= EL_EMC_WALL_3)
-#define IS_SP_CHIP(e)          ((e) == EL_SP_CHIP_SINGLE ||            \
-                                (e) == EL_SP_CHIP_LEFT ||              \
-                                (e) == EL_SP_CHIP_RIGHT ||             \
-                                (e) == EL_SP_CHIP_TOP ||               \
-                                (e) == EL_SP_CHIP_BOTTOM)
-#define IS_SP_HARDWARE_BASE(e) ((e) == EL_SP_HARDWARE_BASE_1 ||        \
-                                (e) == EL_SP_HARDWARE_BASE_2 ||        \
-                                (e) == EL_SP_HARDWARE_BASE_3 ||        \
-                                (e) == EL_SP_HARDWARE_BASE_4 ||        \
-                                (e) == EL_SP_HARDWARE_BASE_5 ||        \
-                                (e) == EL_SP_HARDWARE_BASE_6)
-
-#define IS_DC_STEELWALL_2(e)   ((e) >= EL_DC_STEELWALL_2_LEFT &&       \
-                                (e) <= EL_DC_STEELWALL_2_SINGLE)
+#define IS_FILE_ELEMENT(e)             ((e) >= 0 &&                            \
+                                        (e) <= NUM_FILE_ELEMENTS)
+
+#define IS_DRAWABLE_ELEMENT(e)         ((e) >= 0 &&                            \
+                                        (e) <= NUM_DRAWABLE_ELEMENTS)
+
+#define IS_RUNTIME_ELEMENT(e)          ((e) >= 0 &&                            \
+                                        (e) <= NUM_RUNTIME_ELEMENTS)
+
+#define IS_VALID_ELEMENT(e)            ((e) >= 0 &&                            \
+                                        (e) <= MAX_NUM_ELEMENTS)
+
+#define IS_CUSTOM_ELEMENT(e)           ((e) >= EL_CUSTOM_START &&              \
+                                        (e) <= EL_CUSTOM_END)
+
+#define IS_GROUP_ELEMENT(e)            ((e) >= EL_GROUP_START &&               \
+                                        (e) <= EL_GROUP_END)
+
+#define IS_CLIPBOARD_ELEMENT(e)                ((e) >= EL_INTERNAL_CLIPBOARD_START &&  \
+                                        (e) <= EL_INTERNAL_CLIPBOARD_END)
+
+#define IS_INTERNAL_ELEMENT(e)         ((e) >= EL_INTERNAL_START &&            \
+                                        (e) <= EL_INTERNAL_END)
+
+#define IS_MM_ELEMENT_1(e)             ((e) >= EL_MM_START_1 &&                \
+                                        (e) <= EL_MM_END_1)
+#define IS_MM_ELEMENT_2(e)             ((e) >= EL_MM_START_2 &&                \
+                                        (e) <= EL_MM_END_2)
+#define IS_MM_ELEMENT_3(e)             ((e) >= EL_MM_START_3 &&                \
+                                        (e) <= EL_MM_END_3)
+#define IS_MM_ELEMENT(e)               (IS_MM_ELEMENT_1(e) ||                  \
+                                        IS_MM_ELEMENT_2(e) ||                  \
+                                        IS_MM_ELEMENT_3(e))
+
+#define IS_DF_ELEMENT_1(e)             ((e) >= EL_DF_START_1 &&                \
+                                        (e) <= EL_DF_END_1)
+#define IS_DF_ELEMENT_2(e)             ((e) >= EL_DF_START_2 &&                \
+                                        (e) <= EL_DF_END_2)
+#define IS_DF_ELEMENT(e)               (IS_DF_ELEMENT_1(e) ||                  \
+                                        IS_DF_ELEMENT_2(e))
+
+#define IS_MM_MCDUFFIN(e)              ((e) >= EL_MM_MCDUFFIN_START &&         \
+                                        (e) <= EL_MM_MCDUFFIN_END)
+
+#define IS_DF_LASER(e)                 ((e) >= EL_DF_LASER_START &&            \
+                                        (e) <= EL_DF_LASER_END)
+
+#define IS_MM_WALL(e)                  (((e) >= EL_MM_WALL_START &&            \
+                                         (e) <= EL_MM_WALL_END) ||             \
+                                        ((e) >= EL_DF_WALL_START &&            \
+                                         (e) <= EL_DF_WALL_END))
+
+#define IS_DF_WALL(e)                  ((e) >= EL_DF_WALL_START &&             \
+                                        (e) <= EL_DF_WALL_END)
+
+#define IS_MM_WALL_EDITOR(e)           ((e) == EL_MM_STEEL_WALL ||             \
+                                        (e) == EL_MM_WOODEN_WALL ||            \
+                                        (e) == EL_MM_ICE_WALL ||               \
+                                        (e) == EL_MM_AMOEBA_WALL ||            \
+                                        (e) == EL_DF_STEEL_WALL ||             \
+                                        (e) == EL_DF_WOODEN_WALL)
+
+#define IS_ENVELOPE(e)                 ((e) >= EL_ENVELOPE_1 &&                \
+                                        (e) <= EL_ENVELOPE_4)
+
+#define IS_MM_ENVELOPE(e)              ((e) >= EL_MM_ENVELOPE_1 &&             \
+                                        (e) <= EL_MM_ENVELOPE_4)
+
+#define IS_BALLOON_ELEMENT(e)          ((e) == EL_BALLOON ||                   \
+                                        (e) == EL_BALLOON_SWITCH_LEFT ||       \
+                                        (e) == EL_BALLOON_SWITCH_RIGHT ||      \
+                                        (e) == EL_BALLOON_SWITCH_UP ||         \
+                                        (e) == EL_BALLOON_SWITCH_DOWN ||       \
+                                        (e) == EL_BALLOON_SWITCH_ANY ||        \
+                                        (e) == EL_BALLOON_SWITCH_NONE)
+
+#define IS_RND_KEY(e)                  ((e) >= EL_KEY_1 &&                     \
+                                        (e) <= EL_KEY_4)
+#define IS_EM_KEY(e)                   ((e) >= EL_EM_KEY_1 &&                  \
+                                        (e) <= EL_EM_KEY_4)
+#define IS_EMC_KEY(e)                  ((e) >= EL_EMC_KEY_5 &&                 \
+                                        (e) <= EL_EMC_KEY_8)
+#define IS_KEY(e)                      (IS_RND_KEY(e) ||                       \
+                                        IS_EM_KEY(e) ||                        \
+                                        IS_EMC_KEY(e))
+#define RND_KEY_NR(e)                  ((e) - EL_KEY_1)
+#define EM_KEY_NR(e)                   ((e) - EL_EM_KEY_1)
+#define EMC_KEY_NR(e)                  ((e) - EL_EMC_KEY_5 + 4)
+#define KEY_NR(e)                      (IS_RND_KEY(e) ? RND_KEY_NR(e) :        \
+                                        IS_EM_KEY(e)  ? EM_KEY_NR(e)  :        \
+                                        IS_EMC_KEY(e) ? EMC_KEY_NR(e) : 0)
+
+#define IS_RND_GATE(e)                 ((e) >= EL_GATE_1 &&                    \
+                                        (e) <= EL_GATE_4)
+#define IS_EM_GATE(e)                  ((e) >= EL_EM_GATE_1 &&                 \
+                                        (e) <= EL_EM_GATE_4)
+#define IS_EMC_GATE(e)                 ((e) >= EL_EMC_GATE_5 &&                \
+                                        (e) <= EL_EMC_GATE_8)
+#define IS_DC_GATE(e)                  ((e) == EL_DC_GATE_WHITE)
+#define IS_GATE(e)                     (IS_RND_GATE(e) ||                      \
+                                        IS_EM_GATE(e) ||                       \
+                                        IS_EMC_GATE(e) ||                      \
+                                        IS_DC_GATE(e))
+#define RND_GATE_NR(e)                 ((e) - EL_GATE_1)
+#define EM_GATE_NR(e)                  ((e) - EL_EM_GATE_1)
+#define EMC_GATE_NR(e)                 ((e) - EL_EMC_GATE_5 + 4)
+#define GATE_NR(e)                     (IS_RND_GATE(e) ? RND_GATE_NR(e) :      \
+                                        IS_EM_GATE(e)  ? EM_GATE_NR(e) :       \
+                                        IS_EMC_GATE(e) ? EMC_GATE_NR(e) : 0)
+
+#define IS_RND_GATE_GRAY(e)            ((e) >= EL_GATE_1_GRAY &&               \
+                                        (e) <= EL_GATE_4_GRAY)
+#define IS_RND_GATE_GRAY_ACTIVE(e)     ((e) >= EL_GATE_1_GRAY_ACTIVE &&        \
+                                        (e) <= EL_GATE_4_GRAY_ACTIVE)
+#define IS_EM_GATE_GRAY(e)             ((e) >= EL_EM_GATE_1_GRAY &&            \
+                                        (e) <= EL_EM_GATE_4_GRAY)
+#define IS_EM_GATE_GRAY_ACTIVE(e)      ((e) >= EL_EM_GATE_1_GRAY_ACTIVE &&     \
+                                        (e) <= EL_EM_GATE_4_GRAY_ACTIVE)
+#define IS_EMC_GATE_GRAY(e)            ((e) >= EL_EMC_GATE_5_GRAY &&           \
+                                        (e) <= EL_EMC_GATE_8_GRAY)
+#define IS_EMC_GATE_GRAY_ACTIVE(e)     ((e) >= EL_EMC_GATE_5_GRAY_ACTIVE &&    \
+                                        (e) <= EL_EMC_GATE_8_GRAY_ACTIVE)
+#define IS_DC_GATE_GRAY(e)             ((e) == EL_DC_GATE_WHITE_GRAY)
+#define IS_DC_GATE_GRAY_ACTIVE(e)      ((e) == EL_DC_GATE_WHITE_GRAY_ACTIVE)
+
+#define IS_GATE_GRAY(e)                        (IS_RND_GATE_GRAY(e) ||                 \
+                                        IS_EM_GATE_GRAY(e) ||                  \
+                                        IS_EMC_GATE_GRAY(e) ||                 \
+                                        IS_DC_GATE_GRAY(e))
+#define IS_GATE_GRAY_ACTIVE(e)         (IS_RND_GATE_GRAY_ACTIVE(e) ||          \
+                                        IS_EM_GATE_GRAY_ACTIVE(e) ||           \
+                                        IS_EMC_GATE_GRAY_ACTIVE(e) ||          \
+                                        IS_DC_GATE_GRAY_ACTIVE(e))
+#define RND_GATE_GRAY_NR(e)            ((e) - EL_GATE_1_GRAY)
+#define RND_GATE_GRAY_ACTIVE_NR(e)     ((e) - EL_GATE_1_GRAY_ACTIVE)
+#define EM_GATE_GRAY_NR(e)             ((e) - EL_EM_GATE_1_GRAY)
+#define EM_GATE_GRAY_ACTIVE_NR(e)      ((e) - EL_EM_GATE_1_GRAY_ACTIVE)
+#define EMC_GATE_GRAY_NR(e)            ((e) - EL_EMC_GATE_5_GRAY + 4)
+#define EMC_GATE_GRAY_ACTIVE_NR(e)     ((e) - EL_EMC_GATE_5_GRAY_ACTIVE + 4)
+#define GATE_GRAY_NR(e)                        (IS_RND_GATE_GRAY(e) ? RND_GATE_GRAY_NR(e) :    \
+                                        IS_EM_GATE_GRAY(e)  ? EM_GATE_GRAY_NR(e)  :    \
+                                        IS_EMC_GATE_GRAY(e) ? EMC_GATE_GRAY_NR(e) : 0)
+
+#define RND_ENVELOPE_NR(e)             ((e) - EL_ENVELOPE_1)
+#define MM_ENVELOPE_NR(e)              ((e) - EL_MM_ENVELOPE_1)
+#define ENVELOPE_NR(e)                 (IS_ENVELOPE(e) ? RND_ENVELOPE_NR(e) :  \
+                                        MM_ENVELOPE_NR(e))
+
+#define IS_ACID_POOL_OR_ACID(e)                (IS_ACID_POOL(e) || (e) == EL_ACID)
+
+#define IS_EMC_PILLAR(e)               ((e) >= EL_EMC_WALL_1 &&                \
+                                        (e) <= EL_EMC_WALL_3)
+#define IS_SP_CHIP(e)                  ((e) == EL_SP_CHIP_SINGLE ||            \
+                                        (e) == EL_SP_CHIP_LEFT ||              \
+                                        (e) == EL_SP_CHIP_RIGHT ||             \
+                                        (e) == EL_SP_CHIP_TOP ||               \
+                                        (e) == EL_SP_CHIP_BOTTOM)
+#define IS_SP_HARDWARE_BASE(e)         ((e) == EL_SP_HARDWARE_BASE_1 ||        \
+                                        (e) == EL_SP_HARDWARE_BASE_2 ||        \
+                                        (e) == EL_SP_HARDWARE_BASE_3 ||        \
+                                        (e) == EL_SP_HARDWARE_BASE_4 ||        \
+                                        (e) == EL_SP_HARDWARE_BASE_5 ||        \
+                                        (e) == EL_SP_HARDWARE_BASE_6)
+
+#define IS_DC_STEELWALL_2(e)           ((e) >= EL_DC_STEELWALL_2_LEFT &&       \
+                                        (e) <= EL_DC_STEELWALL_2_SINGLE)
 
 // !!! IMPROVE THIS !!!
 #define IS_EM_ELEMENT(e)       (map_element_EM_to_RND_cave(map_element_RND_to_EM_cave(e)) == (e))
 
-#define MM_WALL_BASE(e)                ((e) & 0xfff0)
-#define MM_WALL_BITS(e)                ((e) & 0x000f)
+#define MM_WALL_BASE(e)                        ((e) & 0xfff0)
+#define MM_WALL_BITS(e)                        ((e) & 0x000f)
 
-#define GFX_ELEMENT(e)         (element_info[e].gfx_element)
+#define GFX_ELEMENT(e)                 (element_info[e].gfx_element)
 
 // !!! CHECK THIS !!!
 #if 1
-#define TILE_GFX_ELEMENT(x, y)                                         \
-                  (GfxElement[x][y] != EL_UNDEFINED &&                 \
-                   Tile[x][y] != EL_EXPLOSION ?                        \
-                   GfxElement[x][y] : Tile[x][y])
+#define TILE_GFX_ELEMENT(x, y)                                                 \
+                                  (GfxElement[x][y] != EL_UNDEFINED &&         \
+                                   Tile[x][y] != EL_EXPLOSION ?                \
+                                   GfxElement[x][y] : Tile[x][y])
 #else
-#define TILE_GFX_ELEMENT(x, y)                                         \
-       GFX_ELEMENT(GfxElement[x][y] != EL_UNDEFINED &&                 \
-                   Tile[x][y] != EL_EXPLOSION ?                        \
-                   GfxElement[x][y] : Tile[x][y])
+#define TILE_GFX_ELEMENT(x, y)                                                 \
+                       GFX_ELEMENT(GfxElement[x][y] != EL_UNDEFINED &&         \
+                                   Tile[x][y] != EL_EXPLOSION ?                \
+                                   GfxElement[x][y] : Tile[x][y])
 #endif
 
 // !!! "use sound" deactivated due to problems with level "bug machine" !!!
 // (solution: add separate "use sound of element" to level file and editor)
 #if 0
-#define SND_ELEMENT(e)         GFX_ELEMENT(e)
+#define SND_ELEMENT(e)                 GFX_ELEMENT(e)
 #else
-#define SND_ELEMENT(e)         (e)
+#define SND_ELEMENT(e)                 (e)
 #endif
 
-#define GROUP_NR(e)            ((e) - EL_GROUP_START)
-#define IS_IN_GROUP(e, nr)     (element_info[e].in_group[nr] == TRUE)
-#define IS_IN_GROUP_EL(e, ge)  (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
+#define GROUP_NR(e)                    ((e) - EL_GROUP_START)
+#define IS_IN_GROUP(e, nr)             (element_info[e].in_group[nr] == TRUE)
+#define IS_IN_GROUP_EL(e, ge)          (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
 
 #define IS_EQUAL_OR_IN_GROUP(e, ge)                                    \
        (ge == EL_ANY_ELEMENT ? TRUE :                                  \
         IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
 
-#define IS_PLAYER(x, y)                (IS_PLAYER_ELEMENT(StorePlayer[x][y]))
-
-#define IS_FREE(x, y)          (Tile[x][y] == EL_EMPTY && !IS_PLAYER(x, y))
-#define IS_FREE_OR_PLAYER(x, y)        (Tile[x][y] == EL_EMPTY)
-
-#define IS_MOVING(x,y)         (MovPos[x][y] != 0)
-#define IS_FALLING(x,y)                (MovPos[x][y] != 0 && MovDir[x][y] == MV_DOWN)
-#define IS_BLOCKED(x,y)                (Tile[x][y] == EL_BLOCKED)
-
-#define IS_MV_DIAGONAL(x)      ((x) & MV_HORIZONTAL && (x) & MV_VERTICAL)
-
-#define EL_CHANGED(e)          ((e) == EL_ROCK           ? EL_EMERALD :    \
-                                (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
-                                (e) == EL_EMERALD        ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_YELLOW ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_RED    ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_PURPLE ? EL_DIAMOND :    \
-                                EL_ROCK)
-#define EL_CHANGED_BD(e)       ((e) == EL_ROCK           ? EL_BD_DIAMOND : \
-                                (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
-                                EL_BD_ROCK)
-#define EL_CHANGED_DC(e)       ((e) == EL_ROCK           ? EL_EMERALD :    \
-                                (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
-                                (e) == EL_EMERALD        ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_YELLOW ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_RED    ? EL_DIAMOND :    \
-                                (e) == EL_EMERALD_PURPLE ? EL_DIAMOND :    \
-                                (e) == EL_PEARL          ? EL_BOMB    :    \
-                                (e) == EL_CRYSTAL        ? EL_CRYSTAL :    \
-                                EL_ROCK)
-#define IS_DRAWABLE(e)         ((e) < EL_BLOCKED)
-#define IS_NOT_DRAWABLE(e)     ((e) >= EL_BLOCKED)
-#define TAPE_IS_EMPTY(x)       ((x).length == 0)
-#define TAPE_IS_STOPPED(x)     (!(x).recording && !(x).playing)
-
-#define PLAYERINFO(x,y)                (&stored_player[StorePlayer[x][y]-EL_PLAYER_1])
-#define SHIELD_ON(p)           ((p)->shield_normal_time_left > 0)
-
-#define ENEMY_PROTECTED_FIELD(x,y)     (IS_PROTECTED(Tile[x][y]) ||       \
+#define IS_PLAYER(x, y)                        (IS_PLAYER_ELEMENT(StorePlayer[x][y]))
+
+#define IS_FREE(x, y)                  (Tile[x][y] == EL_EMPTY && !IS_PLAYER(x, y))
+#define IS_FREE_OR_PLAYER(x, y)                (Tile[x][y] == EL_EMPTY)
+
+#define IS_MOVING(x, y)                        (MovPos[x][y] != 0)
+#define IS_FALLING(x, y)               (MovPos[x][y] != 0 && MovDir[x][y] == MV_DOWN)
+#define IS_BLOCKED(x, y)               (Tile[x][y] == EL_BLOCKED)
+
+#define IS_MV_DIAGONAL(x)              ((x) & MV_HORIZONTAL && (x) & MV_VERTICAL)
+
+#define EL_CHANGED(e)                  ((e) == EL_ROCK           ? EL_EMERALD :    \
+                                        (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
+                                        (e) == EL_EMERALD        ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_YELLOW ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_RED    ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_PURPLE ? EL_DIAMOND :    \
+                                        EL_ROCK)
+#define EL_CHANGED_BD(e)               ((e) == EL_ROCK           ? EL_BD_DIAMOND : \
+                                        (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
+                                        EL_BD_ROCK)
+#define EL_CHANGED_DC(e)               ((e) == EL_ROCK           ? EL_EMERALD :    \
+                                        (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
+                                        (e) == EL_EMERALD        ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_YELLOW ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_RED    ? EL_DIAMOND :    \
+                                        (e) == EL_EMERALD_PURPLE ? EL_DIAMOND :    \
+                                        (e) == EL_PEARL          ? EL_BOMB    :    \
+                                        (e) == EL_CRYSTAL        ? EL_CRYSTAL :    \
+                                        EL_ROCK)
+
+#define IS_BDX_PLAYER_ELEMENT(e)       ((e) == EL_BDX_INBOX ||                 \
+                                        (e) == EL_BDX_PLAYER ||                \
+                                        (e) == EL_BDX_PLAYER_WITH_BOMB ||      \
+                                        (e) == EL_BDX_PLAYER_GLUED ||          \
+                                        (e) == EL_BDX_PLAYER_STIRRING)
+
+#define IS_BD_FIREFLY(e)               ((e) == EL_BD_FIREFLY ||                \
+                                        (e) == EL_BD_FIREFLY_RIGHT ||          \
+                                        (e) == EL_BD_FIREFLY_UP ||             \
+                                        (e) == EL_BD_FIREFLY_LEFT ||           \
+                                        (e) == EL_BD_FIREFLY_DOWN)
+
+#define IS_BDX_FIREFLY_1(e)            ((e) == EL_BDX_FIREFLY_1 ||             \
+                                        (e) == EL_BDX_FIREFLY_1_RIGHT ||       \
+                                        (e) == EL_BDX_FIREFLY_1_UP ||          \
+                                        (e) == EL_BDX_FIREFLY_1_LEFT ||        \
+                                        (e) == EL_BDX_FIREFLY_1_DOWN)
+
+#define IS_BDX_FIREFLY_2(e)            ((e) == EL_BDX_FIREFLY_2 ||             \
+                                        (e) == EL_BDX_FIREFLY_2_RIGHT ||       \
+                                        (e) == EL_BDX_FIREFLY_2_UP ||          \
+                                        (e) == EL_BDX_FIREFLY_2_LEFT ||        \
+                                        (e) == EL_BDX_FIREFLY_2_DOWN)
+
+#define IS_BD_BUTTERFLY(e)             ((e) == EL_BD_BUTTERFLY ||              \
+                                        (e) == EL_BD_BUTTERFLY_RIGHT ||        \
+                                        (e) == EL_BD_BUTTERFLY_UP ||           \
+                                        (e) == EL_BD_BUTTERFLY_LEFT ||         \
+                                        (e) == EL_BD_BUTTERFLY_DOWN)
+
+#define IS_BDX_BUTTERFLY_1(e)          ((e) == EL_BDX_BUTTERFLY_1 ||           \
+                                        (e) == EL_BDX_BUTTERFLY_1_RIGHT ||     \
+                                        (e) == EL_BDX_BUTTERFLY_1_UP ||        \
+                                        (e) == EL_BDX_BUTTERFLY_1_LEFT ||      \
+                                        (e) == EL_BDX_BUTTERFLY_1_DOWN)
+
+#define IS_BDX_BUTTERFLY_2(e)          ((e) == EL_BDX_BUTTERFLY_2 ||           \
+                                        (e) == EL_BDX_BUTTERFLY_2_RIGHT ||     \
+                                        (e) == EL_BDX_BUTTERFLY_2_UP ||        \
+                                        (e) == EL_BDX_BUTTERFLY_2_LEFT ||      \
+                                        (e) == EL_BDX_BUTTERFLY_2_DOWN)
+
+#define IS_BDX_STONEFLY(e)             ((e) == EL_BDX_STONEFLY ||              \
+                                        (e) == EL_BDX_STONEFLY_RIGHT ||        \
+                                        (e) == EL_BDX_STONEFLY_UP ||           \
+                                        (e) == EL_BDX_STONEFLY_LEFT ||         \
+                                        (e) == EL_BDX_STONEFLY_DOWN)
+
+#define IS_BDX_DRAGONFLY(e)            ((e) == EL_BDX_DRAGONFLY ||             \
+                                        (e) == EL_BDX_DRAGONFLY_RIGHT ||       \
+                                        (e) == EL_BDX_DRAGONFLY_UP ||          \
+                                        (e) == EL_BDX_DRAGONFLY_LEFT ||        \
+                                        (e) == EL_BDX_DRAGONFLY_DOWN)
+
+#define IS_BDX_BITER(e)                        ((e) == EL_BDX_BITER ||                 \
+                                        (e) == EL_BDX_BITER_RIGHT ||           \
+                                        (e) == EL_BDX_BITER_UP ||              \
+                                        (e) == EL_BDX_BITER_LEFT ||            \
+                                        (e) == EL_BDX_BITER_DOWN)
+
+#define IS_BDX_EXPANDABLE_WALL(e)      ((e) == EL_BDX_EXPANDABLE_WALL_HORIZONTAL ||            \
+                                        (e) == EL_BDX_EXPANDABLE_WALL_VERTICAL ||              \
+                                        (e) == EL_BDX_EXPANDABLE_WALL_ANY)
+
+#define IS_BDX_EXPANDABLE_STEELWALL(e) ((e) == EL_BDX_EXPANDABLE_STEELWALL_HORIZONTAL ||       \
+                                        (e) == EL_BDX_EXPANDABLE_STEELWALL_VERTICAL ||         \
+                                        (e) == EL_BDX_EXPANDABLE_STEELWALL_ANY)
+
+#define IS_BDX_CONVEYOR_BELT(e)                ((e) == EL_BDX_CONVEYOR_LEFT ||         \
+                                        (e) == EL_BDX_CONVEYOR_LEFT_ACTIVE ||  \
+                                        (e) == EL_BDX_CONVEYOR_RIGHT ||        \
+                                        (e) == EL_BDX_CONVEYOR_RIGHT_ACTIVE)
+
+#define IS_BDX_CONVEYOR_BELT_SWITCH(e) ((e) == EL_BDX_CONVEYOR_SWITCH ||       \
+                                        (e) == EL_BDX_CONVEYOR_SWITCH_ACTIVE ||\
+                                        (e) == EL_BDX_CONVEYOR_DIR_SWITCH ||   \
+                                        (e) == EL_BDX_CONVEYOR_DIR_SWITCH_ACTIVE)
+
+#define IS_BDX_ELEMENT(e)              ((e) >= EL_BDX_START &&                 \
+                                        (e) <= EL_BDX_END)
+
+#define IS_BDX_RUNTIME_ELEMENT(e)      ((e) >= EL_BDX_RUNTIME_START &&         \
+                                        (e) <= EL_BDX_RUNTIME_END)
+
+#define IS_SOKOBAN_OBJECT_OR_FIELD(e)  ((e) == EL_SOKOBAN_OBJECT ||            \
+                                        (e) == EL_SOKOBAN_FIELD_EMPTY ||       \
+                                        (e) == EL_SOKOBAN_FIELD_FULL)
+
+#define IS_DRAWABLE(e)                 ((e) < EL_BLOCKED)
+#define IS_NOT_DRAWABLE(e)             ((e) >= EL_BLOCKED)
+#define TAPE_IS_EMPTY(x)               ((x).length == 0)
+#define TAPE_IS_STOPPED(x)             (!(x).recording && !(x).playing)
+
+#define PLAYERINFO(x, y)               (&stored_player[StorePlayer[x][y] - EL_PLAYER_1])
+#define SHIELD_ON(p)                   ((p)->shield_normal_time_left > 0)
+
+#define ENEMY_PROTECTED_FIELD(x, y)    (IS_PROTECTED(Tile[x][y]) ||                    \
                                         IS_PROTECTED(Back[x][y]))
-#define EXPLOSION_PROTECTED_FIELD(x,y)  (IS_EXPLOSION_PROOF(Tile[x][y]))
-#define PLAYER_ENEMY_PROTECTED(x,y)     (SHIELD_ON(PLAYERINFO(x, y)) ||           \
+#define EXPLOSION_PROTECTED_FIELD(x, y)        (IS_EXPLOSION_PROOF(Tile[x][y]))
+#define PLAYER_ENEMY_PROTECTED(x, y)   (SHIELD_ON(PLAYERINFO(x, y)) ||                 \
                                         ENEMY_PROTECTED_FIELD(x, y))
-#define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) ||           \
+#define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) ||                        \
                                         EXPLOSION_PROTECTED_FIELD(x, y))
 
-#define PLAYER_SWITCHING(p,x,y)        ((p)->is_switching &&                   \
-                                (p)->switch_x == (x) && (p)->switch_y == (y))
+#define PLAYER_SWITCHING(p,x,y)                ((p)->is_switching &&                           \
+                                        (p)->switch_x == (x) && (p)->switch_y == (y))
+
+#define PLAYER_DROPPING(p,x,y)         ((p)->is_dropping &&                            \
+                                        (p)->drop_x == (x) && (p)->drop_y == (y))
 
-#define PLAYER_DROPPING(p,x,y) ((p)->is_dropping &&                    \
-                                (p)->drop_x == (x) && (p)->drop_y == (y))
+#define PLAYER_NR_GFX(g, i)            ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_1))
 
-#define PLAYER_NR_GFX(g,i)     ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_1))
+#define GET_PLAYER_ELEMENT(e)          ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ?     \
+                                        (e) : EL_PLAYER_1)
 
-#define GET_PLAYER_ELEMENT(e)  ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? \
-                                (e) : EL_PLAYER_1)
+#define GET_PLAYER_NR(e)               (GET_PLAYER_ELEMENT(e) - EL_PLAYER_1)
 
-#define GET_PLAYER_NR(e)       (GET_PLAYER_ELEMENT(e) - EL_PLAYER_1)
+#define GET_EMPTY_ELEMENT(i)           ((i) == 0 ? EL_EMPTY_SPACE :                    \
+                                        EL_EMPTY_SPACE_1 + (i) - 1)
 
-#define ANIM_FRAMES(g)         (graphic_info[g].anim_frames)
-#define ANIM_DELAY(g)          (graphic_info[g].anim_delay)
-#define ANIM_MODE(g)           (graphic_info[g].anim_mode)
+#define ANIM_FRAMES(g)                 (graphic_info[g].anim_frames)
+#define ANIM_DELAY(g)                  (graphic_info[g].anim_delay)
+#define ANIM_MODE(g)                   (graphic_info[g].anim_mode)
 
-#define IS_ANIM_MODE_CE(g)     (graphic_info[g].anim_mode & (ANIM_CE_VALUE |  \
-                                                             ANIM_CE_SCORE |  \
-                                                             ANIM_CE_DELAY))
-#define IS_ANIMATED(g)         (ANIM_FRAMES(g) > 1)
-#define IS_NEW_DELAY(f, g)     ((f) % ANIM_DELAY(g) == 0)
-#define IS_NEW_FRAME(f, g)     (IS_ANIMATED(g) && IS_NEW_DELAY(f, g))
-#define IS_NEXT_FRAME(f, g)    (IS_NEW_FRAME(f, g) && (f) > 0)
+#define IS_ANIM_MODE_CE(g)             (graphic_info[g].anim_mode & (ANIM_CE_VALUE |   \
+                                                                     ANIM_CE_SCORE |   \
+                                                                     ANIM_CE_DELAY))
+#define IS_ANIMATED(g)                 (ANIM_FRAMES(g) > 1)
+#define IS_NEW_DELAY(f, g)             ((f) % ANIM_DELAY(g) == 0)
+#define IS_NEW_FRAME(f, g)             (IS_ANIMATED(g) && IS_NEW_DELAY(f, g))
+#define IS_NEXT_FRAME(f, g)            (IS_NEW_FRAME(f, g) && (f) > 0)
 
-#define IS_LOOP_SOUND(s)       (sound_info[s].loop)
-#define IS_LOOP_MUSIC(s)       (music_info[s].loop)
+#define IS_LOOP_SOUND(s)               ((s) >= 0 && sound_info[s].loop)
+#define IS_LOOP_MUSIC(s)               ((s) <  0 || music_info[s].loop)
 
-#define IS_SPECIAL_GFX_ARG(a)  ((a) >= 0 && (a) < NUM_SPECIAL_GFX_ARGS)
+#define IS_SPECIAL_GFX_ARG(a)          ((a) >= 0 && (a) < NUM_SPECIAL_GFX_ARGS)
 
-#define IS_GLOBAL_ANIM_PART(a) ((a) >= 0 && (a) < NUM_GLOBAL_ANIM_PARTS)
+#define IS_GLOBAL_ANIM_PART(a)         ((a) >= 0 && (a) < NUM_GLOBAL_ANIM_PARTS)
 
-#define EL_CASCADE_ACTIVE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e))
-#define EL_CASCADE_INACTIVE(e) (IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
-#define EL_CASCADE_TOGGLE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 :    \
-                                IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
+#define EL_CASCADE_ACTIVE(e)           (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e))
+#define EL_CASCADE_INACTIVE(e)         (IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
+#define EL_CASCADE_TOGGLE(e)           (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 :    \
+                                        IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
 
-#define EL_NAME(e)             ((e) >= 0 ? element_info[e].token_name : "(?)")
-#define MV_TEXT(d)             ((d) == MV_NONE  ? "MV_NONE"  :         \
-                                (d) == MV_LEFT  ? "MV_LEFT"  :         \
-                                (d) == MV_RIGHT ? "MV_RIGHT" :         \
-                                (d) == MV_UP    ? "MV_UP"    :         \
-                                (d) == MV_DOWN  ? "MV_DOWN"  : "(various)")
+#define EL_NAME(e)                     ((e) >= 0 ? element_info[e].token_name : "(?)")
+#define MV_TEXT(d)                     ((d) == MV_NONE  ? "MV_NONE"  :                 \
+                                        (d) == MV_LEFT  ? "MV_LEFT"  :                 \
+                                        (d) == MV_RIGHT ? "MV_RIGHT" :                 \
+                                        (d) == MV_UP    ? "MV_UP"    :                 \
+                                        (d) == MV_DOWN  ? "MV_DOWN"  : "(various)")
 
-#define ELEMENT_ACTIVE(e)      (ActiveElement[e])
-#define BUTTON_ACTIVE(b)       (ActiveButton[b])
-#define FONT_ACTIVE(f)         (ActiveFont[f])
+#define ELEMENT_ACTIVE(e)              (ActiveElement[e])
+#define BUTTON_ACTIVE(b)               (ActiveButton[b])
+#define FONT_ACTIVE(f)                 (ActiveFont[f])
 
 // fundamental game speed values
-#define MICROLEVEL_SCROLL_DELAY        50      // delay for scrolling micro level
-#define MICROLEVEL_LABEL_DELAY 250     // delay for micro level label
+#define MICROLEVEL_SCROLL_DELAY                        50      // delay for scrolling micro level
+#define MICROLEVEL_LABEL_DELAY                 250     // delay for micro level label
 
 // boundaries of arrays etc.
-#define MAX_LEVEL_NAME_LEN     32
-#define MAX_LEVEL_AUTHOR_LEN   32
-#define MAX_ELEMENT_NAME_LEN   32
-#define MAX_TAPES_PER_SET      1024
-#define MAX_SCORE_ENTRIES      100
-#define MAX_NUM_TITLE_IMAGES   5
-#define MAX_NUM_TITLE_MESSAGES 5
-
-#define MAX_NUM_AMOEBA         100
-
-#define NUM_ENVELOPES          4
-#define MIN_ENVELOPE_XSIZE     1
-#define MIN_ENVELOPE_YSIZE     1
-#define MAX_ENVELOPE_XSIZE     30
-#define MAX_ENVELOPE_YSIZE     20
-#define MAX_ENVELOPE_TEXT_LEN  (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE)
-#define MIN_CHANGE_PAGES       1
-#define MAX_CHANGE_PAGES       32
-#define MIN_ELEMENTS_IN_GROUP  1
-#define MAX_ELEMENTS_IN_GROUP  16
-#define MIN_ANDROID_ELEMENTS   1
-#define MAX_ANDROID_ELEMENTS   32
-#define MAX_ANDROID_ELEMENTS_OLD 16    // (extended since version 4.2.0.0)
+#define MAX_LEVEL_NAME_LEN                     32
+#define MAX_LEVEL_AUTHOR_LEN                   32
+#define MAX_ELEMENT_NAME_LEN                   32
+#define MAX_TAPES_PER_SET                      1024
+#define MAX_SCORE_ENTRIES                      100
+#define MAX_NUM_TITLE_IMAGES                   5
+#define MAX_NUM_TITLE_MESSAGES                 5
+
+#define MAX_NUM_AMOEBA                         100
+
+#define NUM_ENVELOPES                          4
+#define MIN_ENVELOPE_XSIZE                     1
+#define MIN_ENVELOPE_YSIZE                     1
+#define MAX_ENVELOPE_XSIZE                     30
+#define MAX_ENVELOPE_YSIZE                     20
+#define MAX_ENVELOPE_TEXT_LEN                  (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE)
+#define MIN_CHANGE_PAGES                       1
+#define MAX_CHANGE_PAGES                       32
+#define MIN_ELEMENTS_IN_GROUP                  1
+#define MAX_ELEMENTS_IN_GROUP                  16
+#define MIN_ANDROID_ELEMENTS                   1
+#define MAX_ANDROID_ELEMENTS                   32
+#define MAX_ANDROID_ELEMENTS_OLD               16      // (extended since version 4.2.0.0)
+
+#define MAX_ISO_DATE_LEN                       10
+#define MAX_PLATFORM_TEXT_LEN                  16
+#define MAX_VERSION_TEXT_LEN                   16
+#define MAX_COUNTRY_CODE_LEN                   2
+#define MAX_COUNTRY_NAME_LEN                   64
 
 // values for elements with content
-#define MIN_ELEMENT_CONTENTS   1
-#define STD_ELEMENT_CONTENTS   4
-#define MAX_ELEMENT_CONTENTS   8
+#define MIN_ELEMENT_CONTENTS                   1
+#define STD_ELEMENT_CONTENTS                   4
+#define MAX_ELEMENT_CONTENTS                   8
+
+#define MIN_MM_BALL_CONTENTS                   1
+#define STD_MM_BALL_CONTENTS                   8
+#define MAX_MM_BALL_CONTENTS                   16
 
 // values for initial player inventory
-#define MIN_INITIAL_INVENTORY_SIZE     1
-#define MAX_INITIAL_INVENTORY_SIZE     8
+#define MIN_INITIAL_INVENTORY_SIZE             1
+#define MAX_INITIAL_INVENTORY_SIZE             8
 
 // often used screen positions
-#define TILESIZE               32
-#define TILEX                  TILESIZE
-#define TILEY                  TILESIZE
-#define TILEX_VAR              TILESIZE_VAR
-#define TILEY_VAR              TILESIZE_VAR
-#define MINI_TILESIZE          (TILESIZE / 2)
-#define MINI_TILEX             MINI_TILESIZE
-#define MINI_TILEY             MINI_TILESIZE
-#define MICRO_TILESIZE         (TILESIZE / 8)
-#define MICRO_TILEX            MICRO_TILESIZE
-#define MICRO_TILEY            MICRO_TILESIZE
-#define MIDPOSX                        (SCR_FIELDX / 2)
-#define MIDPOSY                        (SCR_FIELDY / 2)
-#define FXSIZE                 ((2 + SCR_FIELDX + 2) * TILEX_VAR)
-#define FYSIZE                 ((2 + SCR_FIELDY + 2) * TILEY_VAR)
-
-#define MICROLEVEL_XSIZE       ((STD_LEV_FIELDX + 2) * MICRO_TILEX)
-#define MICROLEVEL_YSIZE       ((STD_LEV_FIELDY + 2) * MICRO_TILEY)
-#define MICROLEVEL_XPOS                (SX + (SXSIZE - MICROLEVEL_XSIZE) / 2)
-#define MICROLEVEL_YPOS                (SY + 12 * TILEY - MICRO_TILEY)
-#define MICROLABEL1_YPOS       (MICROLEVEL_YPOS - 36)
-#define MICROLABEL2_YPOS       (MICROLEVEL_YPOS + MICROLEVEL_YSIZE + 7)
+#define TILESIZE                               32
+#define TILEX                                  TILESIZE
+#define TILEY                                  TILESIZE
+#define TILEX_VAR                              TILESIZE_VAR
+#define TILEY_VAR                              TILESIZE_VAR
+#define MINI_TILESIZE                          (TILESIZE / 2)
+#define MINI_TILEX                             MINI_TILESIZE
+#define MINI_TILEY                             MINI_TILESIZE
+#define MICRO_TILESIZE                         (TILESIZE / 8)
+#define MICRO_TILEX                            MICRO_TILESIZE
+#define MICRO_TILEY                            MICRO_TILESIZE
+#define MIDPOSX                                        (SCR_FIELDX / 2)
+#define MIDPOSY                                        (SCR_FIELDY / 2)
+#define FXSIZE                                 ((2 + SCR_FIELDX + 2) * TILEX_VAR)
+#define FYSIZE                                 ((2 + SCR_FIELDY + 2) * TILEY_VAR)
+
+#define MICROLEVEL_XSIZE                       ((STD_LEV_FIELDX + 2) * MICRO_TILEX)
+#define MICROLEVEL_YSIZE                       ((STD_LEV_FIELDY + 2) * MICRO_TILEY)
+#define MICROLEVEL_XPOS                                (SX + (SXSIZE - MICROLEVEL_XSIZE) / 2)
+#define MICROLEVEL_YPOS                                (SY + 12 * TILEY - MICRO_TILEY)
+#define MICROLABEL1_YPOS                       (MICROLEVEL_YPOS - 36)
+#define MICROLABEL2_YPOS                       (MICROLEVEL_YPOS + MICROLEVEL_YSIZE + 7)
 
 // values for GfxRedraw
 #define GFX_REDRAW_NONE                                (0)
 #define GFX_REDRAW_TILE_TWINKLED               (1 << 3)
 
 // score for elements
-#define SC_EMERALD             0
-#define SC_DIAMOND             1
-#define SC_BUG                 2
-#define SC_SPACESHIP           3
-#define SC_YAMYAM              4
-#define SC_ROBOT               5
-#define SC_PACMAN              6
-#define SC_NUT                 7
-#define SC_DYNAMITE            8
-#define SC_KEY                 9
-#define SC_TIME_BONUS          10
-#define SC_CRYSTAL             11
-#define SC_PEARL               12
-#define SC_SHIELD              13
-#define SC_ELEM_BONUS          14
-#define SC_UNKNOWN_15          15
-
-#define LEVEL_SCORE_ELEMENTS   16      // level elements with score
+#define SC_EMERALD                             0
+#define SC_DIAMOND                             1
+#define SC_BUG                                 2
+#define SC_SPACESHIP                           3
+#define SC_YAMYAM                              4
+#define SC_ROBOT                               5
+#define SC_PACMAN                              6
+#define SC_NUT                                 7
+#define SC_DYNAMITE                            8
+#define SC_KEY                                 9
+#define SC_TIME_BONUS                          10
+#define SC_CRYSTAL                             11
+#define SC_PEARL                               12
+#define SC_SHIELD                              13
+#define SC_ELEM_BONUS                          14
+#define SC_DIAMOND_EXTRA                       15
+
+#define LEVEL_SCORE_ELEMENTS                   16      // level elements with score
 
 
 // "real" level file elements
-#define EL_UNDEFINED                   -1
-
-#define EL_EMPTY_SPACE                 0
-#define EL_EMPTY                       EL_EMPTY_SPACE
-#define EL_SAND                                1
-#define EL_WALL                                2
-#define EL_WALL_SLIPPERY               3
-#define EL_ROCK                                4
-#define EL_KEY_OBSOLETE                        5       // obsolete; now EL_KEY_1
-#define EL_EMERALD                     6
-#define EL_EXIT_CLOSED                 7
-#define EL_PLAYER_OBSOLETE             8       // obsolete; now EL_PLAYER_1
-#define EL_BUG                         9
-#define EL_SPACESHIP                   10
-#define EL_YAMYAM                      11
-#define EL_ROBOT                       12
-#define EL_STEELWALL                   13
-#define EL_DIAMOND                     14
-#define EL_AMOEBA_DEAD                 15
-#define EL_QUICKSAND_EMPTY             16
-#define EL_QUICKSAND_FULL              17
-#define EL_AMOEBA_DROP                 18
-#define EL_BOMB                                19
-#define EL_MAGIC_WALL                  20
-#define EL_SPEED_PILL                  21
-#define EL_ACID                                22
-#define EL_AMOEBA_WET                  23
-#define EL_AMOEBA_DRY                  24
-#define EL_NUT                         25
-#define EL_GAME_OF_LIFE                        26
-#define EL_BIOMAZE                     27
-#define EL_DYNAMITE_ACTIVE             28
-#define EL_STONEBLOCK                  29
-#define EL_ROBOT_WHEEL                 30
-#define EL_ROBOT_WHEEL_ACTIVE          31
-#define EL_KEY_1                       32
-#define EL_KEY_2                       33
-#define EL_KEY_3                       34
-#define EL_KEY_4                       35
-#define EL_GATE_1                      36
-#define EL_GATE_2                      37
-#define EL_GATE_3                      38
-#define EL_GATE_4                      39
-#define EL_GATE_1_GRAY                 40
-#define EL_GATE_2_GRAY                 41
-#define EL_GATE_3_GRAY                 42
-#define EL_GATE_4_GRAY                 43
-#define EL_DYNAMITE                    44
-#define EL_PACMAN                      45
-#define EL_INVISIBLE_WALL              46
-#define EL_LAMP                                47
-#define EL_LAMP_ACTIVE                 48
-#define EL_WALL_EMERALD                        49
-#define EL_WALL_DIAMOND                        50
-#define EL_AMOEBA_FULL                 51
-#define EL_BD_AMOEBA                   52
-#define EL_TIME_ORB_FULL               53
-#define EL_TIME_ORB_EMPTY              54
-#define EL_EXPANDABLE_WALL             55
-#define EL_BD_DIAMOND                  56
-#define EL_EMERALD_YELLOW              57
-#define EL_WALL_BD_DIAMOND             58
-#define EL_WALL_EMERALD_YELLOW         59
-#define EL_DARK_YAMYAM                 60
-#define EL_BD_MAGIC_WALL               61
-#define EL_INVISIBLE_STEELWALL         62
-#define EL_SOKOBAN_FIELD_PLAYER                63
-#define EL_DYNABOMB_INCREASE_NUMBER    64
-#define EL_DYNABOMB_INCREASE_SIZE      65
-#define EL_DYNABOMB_INCREASE_POWER     66
-#define EL_SOKOBAN_OBJECT              67
-#define EL_SOKOBAN_FIELD_EMPTY         68
-#define EL_SOKOBAN_FIELD_FULL          69
-#define EL_BD_BUTTERFLY_RIGHT          70
-#define EL_BD_BUTTERFLY_UP             71
-#define EL_BD_BUTTERFLY_LEFT           72
-#define EL_BD_BUTTERFLY_DOWN           73
-#define EL_BD_FIREFLY_RIGHT            74
-#define EL_BD_FIREFLY_UP               75
-#define EL_BD_FIREFLY_LEFT             76
-#define EL_BD_FIREFLY_DOWN             77
-#define EL_BD_BUTTERFLY_1              EL_BD_BUTTERFLY_DOWN
-#define EL_BD_BUTTERFLY_2              EL_BD_BUTTERFLY_LEFT
-#define EL_BD_BUTTERFLY_3              EL_BD_BUTTERFLY_UP
-#define EL_BD_BUTTERFLY_4              EL_BD_BUTTERFLY_RIGHT
-#define EL_BD_FIREFLY_1                        EL_BD_FIREFLY_LEFT
-#define EL_BD_FIREFLY_2                        EL_BD_FIREFLY_DOWN
-#define EL_BD_FIREFLY_3                        EL_BD_FIREFLY_RIGHT
-#define EL_BD_FIREFLY_4                        EL_BD_FIREFLY_UP
-#define EL_BD_BUTTERFLY                        78
-#define EL_BD_FIREFLY                  79
-#define EL_PLAYER_1                    80
-#define EL_PLAYER_2                    81
-#define EL_PLAYER_3                    82
-#define EL_PLAYER_4                    83
-#define EL_BUG_RIGHT                   84
-#define EL_BUG_UP                      85
-#define EL_BUG_LEFT                    86
-#define EL_BUG_DOWN                    87
-#define EL_SPACESHIP_RIGHT             88
-#define EL_SPACESHIP_UP                        89
-#define EL_SPACESHIP_LEFT              90
-#define EL_SPACESHIP_DOWN              91
-#define EL_PACMAN_RIGHT                        92
-#define EL_PACMAN_UP                   93
-#define EL_PACMAN_LEFT                 94
-#define EL_PACMAN_DOWN                 95
-#define EL_EMERALD_RED                 96
-#define EL_EMERALD_PURPLE              97
-#define EL_WALL_EMERALD_RED            98
-#define EL_WALL_EMERALD_PURPLE         99
-#define EL_ACID_POOL_TOPLEFT           100
-#define EL_ACID_POOL_TOPRIGHT          101
-#define EL_ACID_POOL_BOTTOMLEFT                102
-#define EL_ACID_POOL_BOTTOM            103
-#define EL_ACID_POOL_BOTTOMRIGHT       104
-#define EL_BD_WALL                     105
-#define EL_BD_ROCK                     106
-#define EL_EXIT_OPEN                   107
-#define EL_BLACK_ORB                   108
-#define EL_AMOEBA_TO_DIAMOND           109
-#define EL_MOLE                                110
-#define EL_PENGUIN                     111
-#define EL_SATELLITE                   112
-#define EL_ARROW_LEFT                  113
-#define EL_ARROW_RIGHT                 114
-#define EL_ARROW_UP                    115
-#define EL_ARROW_DOWN                  116
-#define EL_PIG                         117
-#define EL_DRAGON                      118
-
-#define EL_EM_KEY_1_FILE_OBSOLETE      119     // obsolete; now EL_EM_KEY_1
-
-#define EL_CHAR_START                  120
-#define EL_CHAR_ASCII0                 (EL_CHAR_START  - 32)
-#define EL_CHAR_ASCII0_START           (EL_CHAR_ASCII0 + 32)
+#define EL_UNDEFINED                           -1
+
+#define EL_EMPTY_SPACE                         0
+#define EL_EMPTY                               EL_EMPTY_SPACE
+#define EL_SAND                                        1
+#define EL_WALL                                        2
+#define EL_WALL_SLIPPERY                       3
+#define EL_ROCK                                        4
+#define EL_KEY_OBSOLETE                                5       // obsolete; now EL_KEY_1
+#define EL_EMERALD                             6
+#define EL_EXIT_CLOSED                         7
+#define EL_PLAYER_OBSOLETE                     8       // obsolete; now EL_PLAYER_1
+#define EL_BUG                                 9
+#define EL_SPACESHIP                           10
+#define EL_YAMYAM                              11
+#define EL_ROBOT                               12
+#define EL_STEELWALL                           13
+#define EL_DIAMOND                             14
+#define EL_AMOEBA_DEAD                         15
+#define EL_QUICKSAND_EMPTY                     16
+#define EL_QUICKSAND_FULL                      17
+#define EL_AMOEBA_DROP                         18
+#define EL_BOMB                                        19
+#define EL_MAGIC_WALL                          20
+#define EL_SPEED_PILL                          21
+#define EL_ACID                                        22
+#define EL_AMOEBA_WET                          23
+#define EL_AMOEBA_DRY                          24
+#define EL_NUT                                 25
+#define EL_GAME_OF_LIFE                                26
+#define EL_BIOMAZE                             27
+#define EL_DYNAMITE_ACTIVE                     28
+#define EL_STONEBLOCK                          29
+#define EL_ROBOT_WHEEL                         30
+#define EL_ROBOT_WHEEL_ACTIVE                  31
+#define EL_KEY_1                               32
+#define EL_KEY_2                               33
+#define EL_KEY_3                               34
+#define EL_KEY_4                               35
+#define EL_GATE_1                              36
+#define EL_GATE_2                              37
+#define EL_GATE_3                              38
+#define EL_GATE_4                              39
+#define EL_GATE_1_GRAY                         40
+#define EL_GATE_2_GRAY                         41
+#define EL_GATE_3_GRAY                         42
+#define EL_GATE_4_GRAY                         43
+#define EL_DYNAMITE                            44
+#define EL_PACMAN                              45
+#define EL_INVISIBLE_WALL                      46
+#define EL_LAMP                                        47
+#define EL_LAMP_ACTIVE                         48
+#define EL_WALL_EMERALD                                49
+#define EL_WALL_DIAMOND                                50
+#define EL_AMOEBA_FULL                         51
+#define EL_BD_AMOEBA                           52
+#define EL_TIME_ORB_FULL                       53
+#define EL_TIME_ORB_EMPTY                      54
+#define EL_EXPANDABLE_WALL                     55
+#define EL_BD_DIAMOND                          56
+#define EL_EMERALD_YELLOW                      57
+#define EL_WALL_BD_DIAMOND                     58
+#define EL_WALL_EMERALD_YELLOW                 59
+#define EL_DARK_YAMYAM                         60
+#define EL_BD_MAGIC_WALL                       61
+#define EL_INVISIBLE_STEELWALL                 62
+#define EL_SOKOBAN_FIELD_PLAYER                        63
+#define EL_DYNABOMB_INCREASE_NUMBER            64
+#define EL_DYNABOMB_INCREASE_SIZE              65
+#define EL_DYNABOMB_INCREASE_POWER             66
+#define EL_SOKOBAN_OBJECT                      67
+#define EL_SOKOBAN_FIELD_EMPTY                 68
+#define EL_SOKOBAN_FIELD_FULL                  69
+#define EL_BD_BUTTERFLY_RIGHT                  70
+#define EL_BD_BUTTERFLY_UP                     71
+#define EL_BD_BUTTERFLY_LEFT                   72
+#define EL_BD_BUTTERFLY_DOWN                   73
+#define EL_BD_FIREFLY_RIGHT                    74
+#define EL_BD_FIREFLY_UP                       75
+#define EL_BD_FIREFLY_LEFT                     76
+#define EL_BD_FIREFLY_DOWN                     77
+#define EL_BD_BUTTERFLY                                78
+#define EL_BD_FIREFLY                          79
+#define EL_PLAYER_1                            80
+#define EL_PLAYER_2                            81
+#define EL_PLAYER_3                            82
+#define EL_PLAYER_4                            83
+#define EL_BUG_RIGHT                           84
+#define EL_BUG_UP                              85
+#define EL_BUG_LEFT                            86
+#define EL_BUG_DOWN                            87
+#define EL_SPACESHIP_RIGHT                     88
+#define EL_SPACESHIP_UP                                89
+#define EL_SPACESHIP_LEFT                      90
+#define EL_SPACESHIP_DOWN                      91
+#define EL_PACMAN_RIGHT                                92
+#define EL_PACMAN_UP                           93
+#define EL_PACMAN_LEFT                         94
+#define EL_PACMAN_DOWN                         95
+#define EL_EMERALD_RED                         96
+#define EL_EMERALD_PURPLE                      97
+#define EL_WALL_EMERALD_RED                    98
+#define EL_WALL_EMERALD_PURPLE                 99
+#define EL_ACID_POOL_TOPLEFT                   100
+#define EL_ACID_POOL_TOPRIGHT                  101
+#define EL_ACID_POOL_BOTTOMLEFT                        102
+#define EL_ACID_POOL_BOTTOM                    103
+#define EL_ACID_POOL_BOTTOMRIGHT               104
+#define EL_BD_WALL                             105
+#define EL_BD_ROCK                             106
+#define EL_EXIT_OPEN                           107
+#define EL_BLACK_ORB                           108
+#define EL_AMOEBA_TO_DIAMOND                   109
+#define EL_MOLE                                        110
+#define EL_PENGUIN                             111
+#define EL_SATELLITE                           112
+#define EL_ARROW_LEFT                          113
+#define EL_ARROW_RIGHT                         114
+#define EL_ARROW_UP                            115
+#define EL_ARROW_DOWN                          116
+#define EL_PIG                                 117
+#define EL_DRAGON                              118
+
+#define EL_EM_KEY_1_FILE_OBSOLETE              119     // obsolete; now EL_EM_KEY_1
+
+// text character elements
+#define EL_CHAR_START                          120
+#define EL_CHAR_ASCII0                         (EL_CHAR_START  - 32)
+#define EL_CHAR_ASCII0_START                   (EL_CHAR_ASCII0 + 32)
 
 #include "conf_chr.h"  // include auto-generated data structure definitions
 
-#define EL_CHAR_ASCII0_END             (EL_CHAR_ASCII0 + 111)
-#define EL_CHAR_END                    (EL_CHAR_START  + 79)
-
-#define EL_CHAR(c)                     (EL_CHAR_ASCII0 + MAP_FONT_ASCII(c))
-
-#define EL_EXPANDABLE_WALL_HORIZONTAL  200
-#define EL_EXPANDABLE_WALL_VERTICAL    201
-#define EL_EXPANDABLE_WALL_ANY         202
-
-#define EL_EM_GATE_1                   203
-#define EL_EM_GATE_2                   204
-#define EL_EM_GATE_3                   205
-#define EL_EM_GATE_4                   206
-
-#define EL_EM_KEY_2_FILE_OBSOLETE      207     // obsolete; now EL_EM_KEY_2
-#define EL_EM_KEY_3_FILE_OBSOLETE      208     // obsolete; now EL_EM_KEY_3
-#define EL_EM_KEY_4_FILE_OBSOLETE      209     // obsolete; now EL_EM_KEY_4
-
-#define EL_SP_START                    210
-#define EL_SP_EMPTY_SPACE              (EL_SP_START + 0)
-#define EL_SP_EMPTY                    EL_SP_EMPTY_SPACE
-#define EL_SP_ZONK                     (EL_SP_START + 1)
-#define EL_SP_BASE                     (EL_SP_START + 2)
-#define EL_SP_MURPHY                   (EL_SP_START + 3)
-#define EL_SP_INFOTRON                 (EL_SP_START + 4)
-#define EL_SP_CHIP_SINGLE              (EL_SP_START + 5)
-#define EL_SP_HARDWARE_GRAY            (EL_SP_START + 6)
-#define EL_SP_EXIT_CLOSED              (EL_SP_START + 7)
-#define EL_SP_DISK_ORANGE              (EL_SP_START + 8)
-#define EL_SP_PORT_RIGHT               (EL_SP_START + 9)
-#define EL_SP_PORT_DOWN                        (EL_SP_START + 10)
-#define EL_SP_PORT_LEFT                        (EL_SP_START + 11)
-#define EL_SP_PORT_UP                  (EL_SP_START + 12)
-#define EL_SP_GRAVITY_PORT_RIGHT       (EL_SP_START + 13)
-#define EL_SP_GRAVITY_PORT_DOWN                (EL_SP_START + 14)
-#define EL_SP_GRAVITY_PORT_LEFT                (EL_SP_START + 15)
-#define EL_SP_GRAVITY_PORT_UP          (EL_SP_START + 16)
-#define EL_SP_SNIKSNAK                 (EL_SP_START + 17)
-#define EL_SP_DISK_YELLOW              (EL_SP_START + 18)
-#define EL_SP_TERMINAL                 (EL_SP_START + 19)
-#define EL_SP_DISK_RED                 (EL_SP_START + 20)
-#define EL_SP_PORT_VERTICAL            (EL_SP_START + 21)
-#define EL_SP_PORT_HORIZONTAL          (EL_SP_START + 22)
-#define EL_SP_PORT_ANY                 (EL_SP_START + 23)
-#define EL_SP_ELECTRON                 (EL_SP_START + 24)
-#define EL_SP_BUGGY_BASE               (EL_SP_START + 25)
-#define EL_SP_CHIP_LEFT                        (EL_SP_START + 26)
-#define EL_SP_CHIP_RIGHT               (EL_SP_START + 27)
-#define EL_SP_HARDWARE_BASE_1          (EL_SP_START + 28)
-#define EL_SP_HARDWARE_GREEN           (EL_SP_START + 29)
-#define EL_SP_HARDWARE_BLUE            (EL_SP_START + 30)
-#define EL_SP_HARDWARE_RED             (EL_SP_START + 31)
-#define EL_SP_HARDWARE_YELLOW          (EL_SP_START + 32)
-#define EL_SP_HARDWARE_BASE_2          (EL_SP_START + 33)
-#define EL_SP_HARDWARE_BASE_3          (EL_SP_START + 34)
-#define EL_SP_HARDWARE_BASE_4          (EL_SP_START + 35)
-#define EL_SP_HARDWARE_BASE_5          (EL_SP_START + 36)
-#define EL_SP_HARDWARE_BASE_6          (EL_SP_START + 37)
-#define EL_SP_CHIP_TOP                 (EL_SP_START + 38)
-#define EL_SP_CHIP_BOTTOM              (EL_SP_START + 39)
-#define EL_SP_END                      (EL_SP_START + 39)
-
-#define EL_EM_GATE_1_GRAY              250
-#define EL_EM_GATE_2_GRAY              251
-#define EL_EM_GATE_3_GRAY              252
-#define EL_EM_GATE_4_GRAY              253
-
-#define EL_EM_DYNAMITE                 254
-#define EL_EM_DYNAMITE_ACTIVE          255
-
-#define EL_PEARL                       256
-#define EL_CRYSTAL                     257
-#define EL_WALL_PEARL                  258
-#define EL_WALL_CRYSTAL                        259
-#define EL_DC_GATE_WHITE               260
-#define EL_DC_GATE_WHITE_GRAY          261
-#define EL_DC_KEY_WHITE                        262
-#define EL_SHIELD_NORMAL               263
-#define EL_EXTRA_TIME                  264
-#define EL_SWITCHGATE_OPEN             265
-#define EL_SWITCHGATE_CLOSED           266
-#define EL_SWITCHGATE_SWITCH_UP                267
-#define EL_SWITCHGATE_SWITCH_DOWN      268
-
-#define EL_UNUSED_269                  269
-#define EL_UNUSED_270                  270
-
-#define EL_CONVEYOR_BELT_1_LEFT                 271
-#define EL_CONVEYOR_BELT_1_MIDDLE       272
-#define EL_CONVEYOR_BELT_1_RIGHT        273
-#define EL_CONVEYOR_BELT_1_SWITCH_LEFT  274
-#define EL_CONVEYOR_BELT_1_SWITCH_MIDDLE 275
-#define EL_CONVEYOR_BELT_1_SWITCH_RIGHT         276
-#define EL_CONVEYOR_BELT_2_LEFT                 277
-#define EL_CONVEYOR_BELT_2_MIDDLE       278
-#define EL_CONVEYOR_BELT_2_RIGHT        279
-#define EL_CONVEYOR_BELT_2_SWITCH_LEFT  280
-#define EL_CONVEYOR_BELT_2_SWITCH_MIDDLE 281
-#define EL_CONVEYOR_BELT_2_SWITCH_RIGHT         282
-#define EL_CONVEYOR_BELT_3_LEFT                 283
-#define EL_CONVEYOR_BELT_3_MIDDLE       284
-#define EL_CONVEYOR_BELT_3_RIGHT        285
-#define EL_CONVEYOR_BELT_3_SWITCH_LEFT  286
-#define EL_CONVEYOR_BELT_3_SWITCH_MIDDLE 287
-#define EL_CONVEYOR_BELT_3_SWITCH_RIGHT         288
-#define EL_CONVEYOR_BELT_4_LEFT                 289
-#define EL_CONVEYOR_BELT_4_MIDDLE       290
-#define EL_CONVEYOR_BELT_4_RIGHT        291
-#define EL_CONVEYOR_BELT_4_SWITCH_LEFT  292
-#define EL_CONVEYOR_BELT_4_SWITCH_MIDDLE 293
-#define EL_CONVEYOR_BELT_4_SWITCH_RIGHT         294
-#define EL_LANDMINE                    295
-#define EL_ENVELOPE_OBSOLETE           296   // obsolete; now EL_ENVELOPE_1
-#define EL_LIGHT_SWITCH                        297
-#define EL_LIGHT_SWITCH_ACTIVE         298
-#define EL_SIGN_EXCLAMATION            299
-#define EL_SIGN_RADIOACTIVITY          300
-#define EL_SIGN_STOP                   301
-#define EL_SIGN_WHEELCHAIR             302
-#define EL_SIGN_PARKING                        303
-#define EL_SIGN_NO_ENTRY               304
-#define EL_SIGN_UNUSED_1               305
-#define EL_SIGN_GIVE_WAY               306
-#define EL_SIGN_ENTRY_FORBIDDEN                307
-#define EL_SIGN_EMERGENCY_EXIT         308
-#define EL_SIGN_YIN_YANG               309
-#define EL_SIGN_UNUSED_2               310
-#define EL_MOLE_LEFT                   311
-#define EL_MOLE_RIGHT                  312
-#define EL_MOLE_UP                     313
-#define EL_MOLE_DOWN                   314
-#define EL_STEELWALL_SLIPPERY          315
-#define EL_INVISIBLE_SAND              316
-#define EL_DX_UNKNOWN_15               317
-#define EL_DX_UNKNOWN_42               318
-
-#define EL_UNUSED_319                  319
-#define EL_UNUSED_320                  320
-
-#define EL_SHIELD_DEADLY               321
-#define EL_TIMEGATE_OPEN               322
-#define EL_TIMEGATE_CLOSED             323
-#define EL_TIMEGATE_SWITCH_ACTIVE      324
-#define EL_TIMEGATE_SWITCH             325
-
-#define EL_BALLOON                     326
-#define EL_BALLOON_SWITCH_LEFT         327
-#define EL_BALLOON_SWITCH_RIGHT                328
-#define EL_BALLOON_SWITCH_UP           329
-#define EL_BALLOON_SWITCH_DOWN         330
-#define EL_BALLOON_SWITCH_ANY          331
-
-#define EL_EMC_STEELWALL_1             332
-#define EL_EMC_STEELWALL_2             333
-#define EL_EMC_STEELWALL_3             334
-#define EL_EMC_STEELWALL_4             335
-#define EL_EMC_WALL_1                  336
-#define EL_EMC_WALL_2                  337
-#define EL_EMC_WALL_3                  338
-#define EL_EMC_WALL_4                  339
-#define EL_EMC_WALL_5                  340
-#define EL_EMC_WALL_6                  341
-#define EL_EMC_WALL_7                  342
-#define EL_EMC_WALL_8                  343
-
-#define EL_TUBE_ANY                    344
-#define EL_TUBE_VERTICAL               345
-#define EL_TUBE_HORIZONTAL             346
-#define EL_TUBE_VERTICAL_LEFT          347
-#define EL_TUBE_VERTICAL_RIGHT         348
-#define EL_TUBE_HORIZONTAL_UP          349
-#define EL_TUBE_HORIZONTAL_DOWN                350
-#define EL_TUBE_LEFT_UP                        351
-#define EL_TUBE_LEFT_DOWN              352
-#define EL_TUBE_RIGHT_UP               353
-#define EL_TUBE_RIGHT_DOWN             354
-#define EL_SPRING                      355
-#define EL_TRAP                                356
-#define EL_DX_SUPABOMB                 357
-
-#define EL_UNUSED_358                  358
-#define EL_UNUSED_359                  359
+#define EL_CHAR_ASCII0_END                     (EL_CHAR_ASCII0 + 111)
+#define EL_CHAR_END                            (EL_CHAR_START  + 79)
+
+#define EL_CHAR(c)                             (EL_CHAR_ASCII0 + MAP_FONT_ASCII(c))
+
+#define EL_EXPANDABLE_WALL_HORIZONTAL          200
+#define EL_EXPANDABLE_WALL_VERTICAL            201
+#define EL_EXPANDABLE_WALL_ANY                 202
+
+// EM style elements
+#define EL_EM_GATE_1                           203
+#define EL_EM_GATE_2                           204
+#define EL_EM_GATE_3                           205
+#define EL_EM_GATE_4                           206
+
+#define EL_EM_KEY_2_FILE_OBSOLETE              207     // obsolete; now EL_EM_KEY_2
+#define EL_EM_KEY_3_FILE_OBSOLETE              208     // obsolete; now EL_EM_KEY_3
+#define EL_EM_KEY_4_FILE_OBSOLETE              209     // obsolete; now EL_EM_KEY_4
+
+// SP style elements
+#define EL_SP_START                            210
+#define EL_SP_EMPTY_SPACE                      (EL_SP_START + 0)
+#define EL_SP_EMPTY                            EL_SP_EMPTY_SPACE
+#define EL_SP_ZONK                             (EL_SP_START + 1)
+#define EL_SP_BASE                             (EL_SP_START + 2)
+#define EL_SP_MURPHY                           (EL_SP_START + 3)
+#define EL_SP_INFOTRON                         (EL_SP_START + 4)
+#define EL_SP_CHIP_SINGLE                      (EL_SP_START + 5)
+#define EL_SP_HARDWARE_GRAY                    (EL_SP_START + 6)
+#define EL_SP_EXIT_CLOSED                      (EL_SP_START + 7)
+#define EL_SP_DISK_ORANGE                      (EL_SP_START + 8)
+#define EL_SP_PORT_RIGHT                       (EL_SP_START + 9)
+#define EL_SP_PORT_DOWN                                (EL_SP_START + 10)
+#define EL_SP_PORT_LEFT                                (EL_SP_START + 11)
+#define EL_SP_PORT_UP                          (EL_SP_START + 12)
+#define EL_SP_GRAVITY_PORT_RIGHT               (EL_SP_START + 13)
+#define EL_SP_GRAVITY_PORT_DOWN                        (EL_SP_START + 14)
+#define EL_SP_GRAVITY_PORT_LEFT                        (EL_SP_START + 15)
+#define EL_SP_GRAVITY_PORT_UP                  (EL_SP_START + 16)
+#define EL_SP_SNIKSNAK                         (EL_SP_START + 17)
+#define EL_SP_DISK_YELLOW                      (EL_SP_START + 18)
+#define EL_SP_TERMINAL                         (EL_SP_START + 19)
+#define EL_SP_DISK_RED                         (EL_SP_START + 20)
+#define EL_SP_PORT_VERTICAL                    (EL_SP_START + 21)
+#define EL_SP_PORT_HORIZONTAL                  (EL_SP_START + 22)
+#define EL_SP_PORT_ANY                         (EL_SP_START + 23)
+#define EL_SP_ELECTRON                         (EL_SP_START + 24)
+#define EL_SP_BUGGY_BASE                       (EL_SP_START + 25)
+#define EL_SP_CHIP_LEFT                                (EL_SP_START + 26)
+#define EL_SP_CHIP_RIGHT                       (EL_SP_START + 27)
+#define EL_SP_HARDWARE_BASE_1                  (EL_SP_START + 28)
+#define EL_SP_HARDWARE_GREEN                   (EL_SP_START + 29)
+#define EL_SP_HARDWARE_BLUE                    (EL_SP_START + 30)
+#define EL_SP_HARDWARE_RED                     (EL_SP_START + 31)
+#define EL_SP_HARDWARE_YELLOW                  (EL_SP_START + 32)
+#define EL_SP_HARDWARE_BASE_2                  (EL_SP_START + 33)
+#define EL_SP_HARDWARE_BASE_3                  (EL_SP_START + 34)
+#define EL_SP_HARDWARE_BASE_4                  (EL_SP_START + 35)
+#define EL_SP_HARDWARE_BASE_5                  (EL_SP_START + 36)
+#define EL_SP_HARDWARE_BASE_6                  (EL_SP_START + 37)
+#define EL_SP_CHIP_TOP                         (EL_SP_START + 38)
+#define EL_SP_CHIP_BOTTOM                      (EL_SP_START + 39)
+#define EL_SP_END                              (EL_SP_START + 39)
+
+// EM style elements
+#define EL_EM_GATE_1_GRAY                      250
+#define EL_EM_GATE_2_GRAY                      251
+#define EL_EM_GATE_3_GRAY                      252
+#define EL_EM_GATE_4_GRAY                      253
+
+#define EL_EM_DYNAMITE                         254
+#define EL_EM_DYNAMITE_ACTIVE                  255
+
+// DC2 style elements
+#define EL_PEARL                               256
+#define EL_CRYSTAL                             257
+#define EL_WALL_PEARL                          258
+#define EL_WALL_CRYSTAL                                259
+#define EL_DC_GATE_WHITE                       260
+#define EL_DC_GATE_WHITE_GRAY                  261
+#define EL_DC_KEY_WHITE                                262
+#define EL_SHIELD_NORMAL                       263
+#define EL_EXTRA_TIME                          264
+#define EL_SWITCHGATE_OPEN                     265
+#define EL_SWITCHGATE_CLOSED                   266
+#define EL_SWITCHGATE_SWITCH_UP                        267
+#define EL_SWITCHGATE_SWITCH_DOWN              268
+
+#define EL_UNUSED_269                          269
+#define EL_UNUSED_270                          270
+
+#define EL_CONVEYOR_BELT_1_LEFT                        271
+#define EL_CONVEYOR_BELT_1_MIDDLE              272
+#define EL_CONVEYOR_BELT_1_RIGHT               273
+#define EL_CONVEYOR_BELT_1_SWITCH_LEFT         274
+#define EL_CONVEYOR_BELT_1_SWITCH_MIDDLE       275
+#define EL_CONVEYOR_BELT_1_SWITCH_RIGHT                276
+#define EL_CONVEYOR_BELT_2_LEFT                        277
+#define EL_CONVEYOR_BELT_2_MIDDLE              278
+#define EL_CONVEYOR_BELT_2_RIGHT               279
+#define EL_CONVEYOR_BELT_2_SWITCH_LEFT         280
+#define EL_CONVEYOR_BELT_2_SWITCH_MIDDLE       281
+#define EL_CONVEYOR_BELT_2_SWITCH_RIGHT                282
+#define EL_CONVEYOR_BELT_3_LEFT                        283
+#define EL_CONVEYOR_BELT_3_MIDDLE              284
+#define EL_CONVEYOR_BELT_3_RIGHT               285
+#define EL_CONVEYOR_BELT_3_SWITCH_LEFT         286
+#define EL_CONVEYOR_BELT_3_SWITCH_MIDDLE       287
+#define EL_CONVEYOR_BELT_3_SWITCH_RIGHT                288
+#define EL_CONVEYOR_BELT_4_LEFT                        289
+#define EL_CONVEYOR_BELT_4_MIDDLE              290
+#define EL_CONVEYOR_BELT_4_RIGHT               291
+#define EL_CONVEYOR_BELT_4_SWITCH_LEFT         292
+#define EL_CONVEYOR_BELT_4_SWITCH_MIDDLE       293
+#define EL_CONVEYOR_BELT_4_SWITCH_RIGHT                294
+#define EL_LANDMINE                            295
+#define EL_ENVELOPE_OBSOLETE                   296     // obsolete; now EL_ENVELOPE_1
+#define EL_LIGHT_SWITCH                                297
+#define EL_LIGHT_SWITCH_ACTIVE                 298
+#define EL_SIGN_EXCLAMATION                    299
+#define EL_SIGN_RADIOACTIVITY                  300
+#define EL_SIGN_STOP                           301
+#define EL_SIGN_WHEELCHAIR                     302
+#define EL_SIGN_PARKING                                303
+#define EL_SIGN_NO_ENTRY                       304
+#define EL_SIGN_UNUSED_1                       305
+#define EL_SIGN_GIVE_WAY                       306
+#define EL_SIGN_ENTRY_FORBIDDEN                        307
+#define EL_SIGN_EMERGENCY_EXIT                 308
+#define EL_SIGN_YIN_YANG                       309
+#define EL_SIGN_UNUSED_2                       310
+#define EL_MOLE_LEFT                           311
+#define EL_MOLE_RIGHT                          312
+#define EL_MOLE_UP                             313
+#define EL_MOLE_DOWN                           314
+#define EL_STEELWALL_SLIPPERY                  315
+#define EL_INVISIBLE_SAND                      316
+#define EL_DX_UNKNOWN_15                       317
+#define EL_DX_UNKNOWN_42                       318
+
+#define EL_UNUSED_319                          319
+#define EL_UNUSED_320                          320
+
+#define EL_SHIELD_DEADLY                       321
+#define EL_TIMEGATE_OPEN                       322
+#define EL_TIMEGATE_CLOSED                     323
+#define EL_TIMEGATE_SWITCH_ACTIVE              324
+#define EL_TIMEGATE_SWITCH                     325
+
+// EMC style elements
+#define EL_BALLOON                             326
+#define EL_BALLOON_SWITCH_LEFT                 327
+#define EL_BALLOON_SWITCH_RIGHT                        328
+#define EL_BALLOON_SWITCH_UP                   329
+#define EL_BALLOON_SWITCH_DOWN                 330
+#define EL_BALLOON_SWITCH_ANY                  331
+
+#define EL_EMC_STEELWALL_1                     332
+#define EL_EMC_STEELWALL_2                     333
+#define EL_EMC_STEELWALL_3                     334
+#define EL_EMC_STEELWALL_4                     335
+#define EL_EMC_WALL_1                          336
+#define EL_EMC_WALL_2                          337
+#define EL_EMC_WALL_3                          338
+#define EL_EMC_WALL_4                          339
+#define EL_EMC_WALL_5                          340
+#define EL_EMC_WALL_6                          341
+#define EL_EMC_WALL_7                          342
+#define EL_EMC_WALL_8                          343
+
+// DX style elements
+#define EL_TUBE_ANY                            344
+#define EL_TUBE_VERTICAL                       345
+#define EL_TUBE_HORIZONTAL                     346
+#define EL_TUBE_VERTICAL_LEFT                  347
+#define EL_TUBE_VERTICAL_RIGHT                 348
+#define EL_TUBE_HORIZONTAL_UP                  349
+#define EL_TUBE_HORIZONTAL_DOWN                        350
+#define EL_TUBE_LEFT_UP                                351
+#define EL_TUBE_LEFT_DOWN                      352
+#define EL_TUBE_RIGHT_UP                       353
+#define EL_TUBE_RIGHT_DOWN                     354
+#define EL_SPRING                              355
+#define EL_TRAP                                        356
+#define EL_DX_SUPABOMB                         357
+
+#define EL_UNUSED_358                          358
+#define EL_UNUSED_359                          359
 
 // ---------- begin of custom elements section --------------------------------
-#define EL_CUSTOM_START                        360
+#define EL_CUSTOM_START                                360
 
 #include "conf_cus.h"  // include auto-generated data structure definitions
 
-#define NUM_CUSTOM_ELEMENTS            256
-#define EL_CUSTOM_END                  615
+#define NUM_CUSTOM_ELEMENTS                    256
+#define EL_CUSTOM_END                          615
 // ---------- end of custom elements section ----------------------------------
 
-#define EL_EM_KEY_1                    616
-#define EL_EM_KEY_2                    617
-#define EL_EM_KEY_3                    618
-#define EL_EM_KEY_4                    619
-#define EL_ENVELOPE_1                  620
-#define EL_ENVELOPE_2                  621
-#define EL_ENVELOPE_3                  622
-#define EL_ENVELOPE_4                  623
+// EM style elements
+#define EL_EM_KEY_1                            616
+#define EL_EM_KEY_2                            617
+#define EL_EM_KEY_3                            618
+#define EL_EM_KEY_4                            619
+
+// DC2 style elements
+#define EL_ENVELOPE_1                          620
+#define EL_ENVELOPE_2                          621
+#define EL_ENVELOPE_3                          622
+#define EL_ENVELOPE_4                          623
 
 // ---------- begin of group elements section ---------------------------------
-#define EL_GROUP_START                 624
+#define EL_GROUP_START                         624
 
 #include "conf_grp.h"  // include auto-generated data structure definitions
 
-#define NUM_GROUP_ELEMENTS             32
-#define EL_GROUP_END                   655
-// ---------- end of custom elements section ----------------------------------
+#define NUM_GROUP_ELEMENTS                     32
+#define EL_GROUP_END                           655
+// ---------- end of group elements section -----------------------------------
 
-#define EL_UNKNOWN                     656
-#define EL_TRIGGER_ELEMENT             657
-#define EL_TRIGGER_PLAYER              658
+#define EL_UNKNOWN                             656
+#define EL_TRIGGER_ELEMENT                     657
+#define EL_TRIGGER_PLAYER                      658
 
 // SP style elements
-#define EL_SP_GRAVITY_ON_PORT_RIGHT    659
-#define EL_SP_GRAVITY_ON_PORT_DOWN     660
-#define EL_SP_GRAVITY_ON_PORT_LEFT     661
-#define EL_SP_GRAVITY_ON_PORT_UP       662
-#define EL_SP_GRAVITY_OFF_PORT_RIGHT   663
-#define EL_SP_GRAVITY_OFF_PORT_DOWN    664
-#define EL_SP_GRAVITY_OFF_PORT_LEFT    665
-#define EL_SP_GRAVITY_OFF_PORT_UP      666
+#define EL_SP_GRAVITY_ON_PORT_RIGHT            659
+#define EL_SP_GRAVITY_ON_PORT_DOWN             660
+#define EL_SP_GRAVITY_ON_PORT_LEFT             661
+#define EL_SP_GRAVITY_ON_PORT_UP               662
+#define EL_SP_GRAVITY_OFF_PORT_RIGHT           663
+#define EL_SP_GRAVITY_OFF_PORT_DOWN            664
+#define EL_SP_GRAVITY_OFF_PORT_LEFT            665
+#define EL_SP_GRAVITY_OFF_PORT_UP              666
 
 // EMC style elements
-#define EL_BALLOON_SWITCH_NONE         667
-#define EL_EMC_GATE_5                  668
-#define EL_EMC_GATE_6                  669
-#define EL_EMC_GATE_7                  670
-#define EL_EMC_GATE_8                  671
-#define EL_EMC_GATE_5_GRAY             672
-#define EL_EMC_GATE_6_GRAY             673
-#define EL_EMC_GATE_7_GRAY             674
-#define EL_EMC_GATE_8_GRAY             675
-#define EL_EMC_KEY_5                   676
-#define EL_EMC_KEY_6                   677
-#define EL_EMC_KEY_7                   678
-#define EL_EMC_KEY_8                   679
-#define EL_EMC_ANDROID                 680
-#define EL_EMC_GRASS                   681
-#define EL_EMC_MAGIC_BALL              682
-#define EL_EMC_MAGIC_BALL_ACTIVE       683
-#define EL_EMC_MAGIC_BALL_SWITCH       684
-#define EL_EMC_MAGIC_BALL_SWITCH_ACTIVE        685
-#define EL_EMC_SPRING_BUMPER           686
-#define EL_EMC_PLANT                   687
-#define EL_EMC_LENSES                  688
-#define EL_EMC_MAGNIFIER               689
-#define EL_EMC_WALL_9                  690
-#define EL_EMC_WALL_10                 691
-#define EL_EMC_WALL_11                 692
-#define EL_EMC_WALL_12                 693
-#define EL_EMC_WALL_13                 694
-#define EL_EMC_WALL_14                 695
-#define EL_EMC_WALL_15                 696
-#define EL_EMC_WALL_16                 697
-#define EL_EMC_WALL_SLIPPERY_1         698
-#define EL_EMC_WALL_SLIPPERY_2         699
-#define EL_EMC_WALL_SLIPPERY_3         700
-#define EL_EMC_WALL_SLIPPERY_4         701
-#define EL_EMC_FAKE_GRASS              702
-#define EL_EMC_FAKE_ACID               703
-#define EL_EMC_DRIPPER                 704
-
-#define EL_TRIGGER_CE_VALUE            705
-#define EL_TRIGGER_CE_SCORE            706
-#define EL_CURRENT_CE_VALUE            707
-#define EL_CURRENT_CE_SCORE            708
-
-#define EL_YAMYAM_LEFT                 709
-#define EL_YAMYAM_RIGHT                        710
-#define EL_YAMYAM_UP                   711
-#define EL_YAMYAM_DOWN                 712
-
-#define EL_BD_EXPANDABLE_WALL          713
-
-#define EL_PREV_CE_8                   714
-#define EL_PREV_CE_7                   715
-#define EL_PREV_CE_6                   716
-#define EL_PREV_CE_5                   717
-#define EL_PREV_CE_4                   718
-#define EL_PREV_CE_3                   719
-#define EL_PREV_CE_2                   720
-#define EL_PREV_CE_1                   721
-#define EL_SELF                                722
-#define EL_NEXT_CE_1                   723
-#define EL_NEXT_CE_2                   724
-#define EL_NEXT_CE_3                   725
-#define EL_NEXT_CE_4                   726
-#define EL_NEXT_CE_5                   727
-#define EL_NEXT_CE_6                   728
-#define EL_NEXT_CE_7                   729
-#define EL_NEXT_CE_8                   730
-#define EL_ANY_ELEMENT                 731
-
-#define EL_STEEL_CHAR_START            732
-#define EL_STEEL_CHAR_ASCII0           (EL_STEEL_CHAR_START  - 32)
-#define EL_STEEL_CHAR_ASCII0_START     (EL_STEEL_CHAR_ASCII0 + 32)
+#define EL_BALLOON_SWITCH_NONE                 667
+#define EL_EMC_GATE_5                          668
+#define EL_EMC_GATE_6                          669
+#define EL_EMC_GATE_7                          670
+#define EL_EMC_GATE_8                          671
+#define EL_EMC_GATE_5_GRAY                     672
+#define EL_EMC_GATE_6_GRAY                     673
+#define EL_EMC_GATE_7_GRAY                     674
+#define EL_EMC_GATE_8_GRAY                     675
+#define EL_EMC_KEY_5                           676
+#define EL_EMC_KEY_6                           677
+#define EL_EMC_KEY_7                           678
+#define EL_EMC_KEY_8                           679
+#define EL_EMC_ANDROID                         680
+#define EL_EMC_GRASS                           681
+#define EL_EMC_MAGIC_BALL                      682
+#define EL_EMC_MAGIC_BALL_ACTIVE               683
+#define EL_EMC_MAGIC_BALL_SWITCH               684
+#define EL_EMC_MAGIC_BALL_SWITCH_ACTIVE                685
+#define EL_EMC_SPRING_BUMPER                   686
+#define EL_EMC_PLANT                           687
+#define EL_EMC_LENSES                          688
+#define EL_EMC_MAGNIFIER                       689
+#define EL_EMC_WALL_9                          690
+#define EL_EMC_WALL_10                         691
+#define EL_EMC_WALL_11                         692
+#define EL_EMC_WALL_12                         693
+#define EL_EMC_WALL_13                         694
+#define EL_EMC_WALL_14                         695
+#define EL_EMC_WALL_15                         696
+#define EL_EMC_WALL_16                         697
+#define EL_EMC_WALL_SLIPPERY_1                 698
+#define EL_EMC_WALL_SLIPPERY_2                 699
+#define EL_EMC_WALL_SLIPPERY_3                 700
+#define EL_EMC_WALL_SLIPPERY_4                 701
+#define EL_EMC_FAKE_GRASS                      702
+#define EL_EMC_FAKE_ACID                       703
+#define EL_EMC_DRIPPER                         704
+
+#define EL_TRIGGER_CE_VALUE                    705
+#define EL_TRIGGER_CE_SCORE                    706
+#define EL_CURRENT_CE_VALUE                    707
+#define EL_CURRENT_CE_SCORE                    708
+
+#define EL_YAMYAM_LEFT                         709
+#define EL_YAMYAM_RIGHT                                710
+#define EL_YAMYAM_UP                           711
+#define EL_YAMYAM_DOWN                         712
+
+#define EL_BD_EXPANDABLE_WALL                  713
+
+// reference elements
+#define EL_PREV_CE_8                           714
+#define EL_PREV_CE_7                           715
+#define EL_PREV_CE_6                           716
+#define EL_PREV_CE_5                           717
+#define EL_PREV_CE_4                           718
+#define EL_PREV_CE_3                           719
+#define EL_PREV_CE_2                           720
+#define EL_PREV_CE_1                           721
+#define EL_SELF                                        722
+#define EL_NEXT_CE_1                           723
+#define EL_NEXT_CE_2                           724
+#define EL_NEXT_CE_3                           725
+#define EL_NEXT_CE_4                           726
+#define EL_NEXT_CE_5                           727
+#define EL_NEXT_CE_6                           728
+#define EL_NEXT_CE_7                           729
+#define EL_NEXT_CE_8                           730
+#define EL_ANY_ELEMENT                         731
+
+// text character elements
+#define EL_STEEL_CHAR_START                    732
+#define EL_STEEL_CHAR_ASCII0                   (EL_STEEL_CHAR_START  - 32)
+#define EL_STEEL_CHAR_ASCII0_START             (EL_STEEL_CHAR_ASCII0 + 32)
 
 // (auto-generated data structure definitions included with normal chars)
 
-#define EL_STEEL_CHAR_ASCII0_END       (EL_STEEL_CHAR_ASCII0 + 111)
-#define EL_STEEL_CHAR_END              (EL_STEEL_CHAR_START  + 79)
-
-#define EL_STEEL_CHAR(c)               (EL_STEEL_CHAR_ASCII0+MAP_FONT_ASCII(c))
-
-#define EL_SPERMS                      812
-#define EL_BULLET                      813
-#define EL_HEART                       814
-#define EL_CROSS                       815
-#define EL_FRANKIE                     816
-#define EL_SIGN_SPERMS                 817
-#define EL_SIGN_BULLET                 818
-#define EL_SIGN_HEART                  819
-#define EL_SIGN_CROSS                  820
-#define EL_SIGN_FRANKIE                        821
-
-#define EL_STEEL_EXIT_CLOSED           822
-#define EL_STEEL_EXIT_OPEN             823
-
-#define EL_DC_STEELWALL_1_LEFT         824
-#define EL_DC_STEELWALL_1_RIGHT                825
-#define EL_DC_STEELWALL_1_TOP          826
-#define EL_DC_STEELWALL_1_BOTTOM       827
-#define EL_DC_STEELWALL_1_HORIZONTAL   828
-#define EL_DC_STEELWALL_1_VERTICAL     829
-#define EL_DC_STEELWALL_1_TOPLEFT      830
-#define EL_DC_STEELWALL_1_TOPRIGHT     831
-#define EL_DC_STEELWALL_1_BOTTOMLEFT   832
-#define EL_DC_STEELWALL_1_BOTTOMRIGHT  833
-#define EL_DC_STEELWALL_1_TOPLEFT_2    834
-#define EL_DC_STEELWALL_1_TOPRIGHT_2   835
-#define EL_DC_STEELWALL_1_BOTTOMLEFT_2 836
-#define EL_DC_STEELWALL_1_BOTTOMRIGHT_2        837
-
-#define EL_DC_STEELWALL_2_LEFT         838
-#define EL_DC_STEELWALL_2_RIGHT                839
-#define EL_DC_STEELWALL_2_TOP          840
-#define EL_DC_STEELWALL_2_BOTTOM       841
-#define EL_DC_STEELWALL_2_HORIZONTAL   842
-#define EL_DC_STEELWALL_2_VERTICAL     843
-#define EL_DC_STEELWALL_2_MIDDLE       844
-#define EL_DC_STEELWALL_2_SINGLE       845
-
-#define EL_DC_SWITCHGATE_SWITCH_UP     846
-#define EL_DC_SWITCHGATE_SWITCH_DOWN   847
-#define EL_DC_TIMEGATE_SWITCH          848
-#define EL_DC_TIMEGATE_SWITCH_ACTIVE   849
-
-#define EL_DC_LANDMINE                 850
-
-#define EL_EXPANDABLE_STEELWALL                   851
-#define EL_EXPANDABLE_STEELWALL_HORIZONTAL 852
-#define EL_EXPANDABLE_STEELWALL_VERTICAL   853
-#define EL_EXPANDABLE_STEELWALL_ANY       854
-
-#define EL_EM_EXIT_CLOSED              855
-#define EL_EM_EXIT_OPEN                        856
-#define EL_EM_STEEL_EXIT_CLOSED                857
-#define EL_EM_STEEL_EXIT_OPEN          858
-
-#define EL_DC_GATE_FAKE_GRAY           859
-
-#define EL_DC_MAGIC_WALL               860
-
-#define EL_QUICKSAND_FAST_EMPTY                861
-#define EL_QUICKSAND_FAST_FULL         862
-
-#define EL_FROM_LEVEL_TEMPLATE         863
-
-#define EL_MM_START                    864
-#define EL_MM_START_1                  EL_MM_START
-
-#define EL_MM_EMPTY_SPACE              (EL_MM_START + 0)
-#define EL_MM_EMPTY                    EL_MM_EMPTY_SPACE
-#define EL_MM_MIRROR_START             (EL_MM_START + 1)
-#define EL_MM_MIRROR_1                 (EL_MM_MIRROR_START + 0)
-#define EL_MM_MIRROR_2                 (EL_MM_MIRROR_START + 1)
-#define EL_MM_MIRROR_3                 (EL_MM_MIRROR_START + 2)
-#define EL_MM_MIRROR_4                 (EL_MM_MIRROR_START + 3)
-#define EL_MM_MIRROR_5                 (EL_MM_MIRROR_START + 4)
-#define EL_MM_MIRROR_6                 (EL_MM_MIRROR_START + 5)
-#define EL_MM_MIRROR_7                 (EL_MM_MIRROR_START + 6)
-#define EL_MM_MIRROR_8                 (EL_MM_MIRROR_START + 7)
-#define EL_MM_MIRROR_9                 (EL_MM_MIRROR_START + 8)
-#define EL_MM_MIRROR_10                        (EL_MM_MIRROR_START + 9)
-#define EL_MM_MIRROR_11                        (EL_MM_MIRROR_START + 10)
-#define EL_MM_MIRROR_12                        (EL_MM_MIRROR_START + 11)
-#define EL_MM_MIRROR_13                        (EL_MM_MIRROR_START + 12)
-#define EL_MM_MIRROR_14                        (EL_MM_MIRROR_START + 13)
-#define EL_MM_MIRROR_15                        (EL_MM_MIRROR_START + 14)
-#define EL_MM_MIRROR_16                        (EL_MM_MIRROR_START + 15)
-#define EL_MM_MIRROR_END               EL_MM_MIRROR_15
-#define EL_MM_STEEL_GRID_FIXED_START   (EL_MM_START + 17)
-#define EL_MM_STEEL_GRID_FIXED_1       (EL_MM_STEEL_GRID_FIXED_START + 0)
-#define EL_MM_STEEL_GRID_FIXED_2       (EL_MM_STEEL_GRID_FIXED_START + 1)
-#define EL_MM_STEEL_GRID_FIXED_3       (EL_MM_STEEL_GRID_FIXED_START + 2)
-#define EL_MM_STEEL_GRID_FIXED_4       (EL_MM_STEEL_GRID_FIXED_START + 3)
-#define EL_MM_STEEL_GRID_FIXED_END     EL_MM_STEEL_GRID_FIXED_03
-#define EL_MM_MCDUFFIN_START           (EL_MM_START + 21)
-#define EL_MM_MCDUFFIN_RIGHT           (EL_MM_MCDUFFIN_START + 0)
-#define EL_MM_MCDUFFIN_UP              (EL_MM_MCDUFFIN_START + 1)
-#define EL_MM_MCDUFFIN_LEFT            (EL_MM_MCDUFFIN_START + 2)
-#define EL_MM_MCDUFFIN_DOWN            (EL_MM_MCDUFFIN_START + 3)
-#define EL_MM_MCDUFFIN_END             EL_MM_MCDUFFIN_DOWN
-#define EL_MM_EXIT_CLOSED              (EL_MM_START + 25)
-#define EL_MM_EXIT_OPENING_1           (EL_MM_START + 26)
-#define EL_MM_EXIT_OPENING_2           (EL_MM_START + 27)
-#define EL_MM_EXIT_OPEN                        (EL_MM_START + 28)
-#define EL_MM_KETTLE                   (EL_MM_START + 29)
-#define EL_MM_BOMB                     (EL_MM_START + 30)
-#define EL_MM_PRISM                    (EL_MM_START + 31)
-#define EL_MM_WALL_START               (EL_MM_START + 32)
-#define EL_MM_WALL_EMPTY               EL_MM_WALL_START
-#define EL_MM_WALL_00                  EL_MM_WALL_START
-#define EL_MM_STEEL_WALL_START         EL_MM_WALL_00
-#define EL_MM_STEEL_WALL_1             EL_MM_STEEL_WALL_START
-#define EL_MM_WALL_15                  (EL_MM_START + 47)
-#define EL_MM_STEEL_WALL_END           EL_MM_WALL_15
-#define EL_MM_WALL_16                  (EL_MM_START + 48)
-#define EL_MM_WOODEN_WALL_START                EL_MM_WALL_16
-#define EL_MM_WOODEN_WALL_1            EL_MM_WOODEN_WALL_START
-#define EL_MM_WALL_31                  (EL_MM_START + 63)
-#define EL_MM_WOODEN_WALL_END          EL_MM_WALL_31
-#define EL_MM_WALL_32                  (EL_MM_START + 64)
-#define EL_MM_ICE_WALL_START           EL_MM_WALL_32
-#define EL_MM_ICE_WALL_1               EL_MM_ICE_WALL_START
-#define EL_MM_WALL_47                  (EL_MM_START + 79)
-#define EL_MM_ICE_WALL_END             EL_MM_WALL_47
-#define EL_MM_WALL_48                  (EL_MM_START + 80)
-#define EL_MM_AMOEBA_WALL_START                EL_MM_WALL_48
-#define EL_MM_AMOEBA_WALL_1            EL_MM_AMOEBA_WALL_START
-#define EL_MM_WALL_63                  (EL_MM_START + 95)
-#define EL_MM_AMOEBA_WALL_END          EL_MM_WALL_63
-#define EL_MM_WALL_END                 EL_MM_WALL_63
-#define EL_MM_WOODEN_BLOCK             (EL_MM_START + 96)
-#define EL_MM_GRAY_BALL                        (EL_MM_START + 97)
-#define EL_MM_TELEPORTER_START         (EL_MM_START + 98)
-#define EL_MM_TELEPORTER_1             (EL_MM_TELEPORTER_START + 0)
-#define EL_MM_TELEPORTER_2             (EL_MM_TELEPORTER_START + 1)
-#define EL_MM_TELEPORTER_3             (EL_MM_TELEPORTER_START + 2)
-#define EL_MM_TELEPORTER_4             (EL_MM_TELEPORTER_START + 3)
-#define EL_MM_TELEPORTER_5             (EL_MM_TELEPORTER_START + 4)
-#define EL_MM_TELEPORTER_6             (EL_MM_TELEPORTER_START + 5)
-#define EL_MM_TELEPORTER_7             (EL_MM_TELEPORTER_START + 6)
-#define EL_MM_TELEPORTER_8             (EL_MM_TELEPORTER_START + 7)
-#define EL_MM_TELEPORTER_9             (EL_MM_TELEPORTER_START + 8)
-#define EL_MM_TELEPORTER_10            (EL_MM_TELEPORTER_START + 9)
-#define EL_MM_TELEPORTER_11            (EL_MM_TELEPORTER_START + 10)
-#define EL_MM_TELEPORTER_12            (EL_MM_TELEPORTER_START + 11)
-#define EL_MM_TELEPORTER_13            (EL_MM_TELEPORTER_START + 12)
-#define EL_MM_TELEPORTER_14            (EL_MM_TELEPORTER_START + 13)
-#define EL_MM_TELEPORTER_15            (EL_MM_TELEPORTER_START + 14)
-#define EL_MM_TELEPORTER_16            (EL_MM_TELEPORTER_START + 15)
-#define EL_MM_TELEPORTER_END           EL_MM_TELEPORTER_15
-#define EL_MM_FUSE_ACTIVE              (EL_MM_START + 114)
-#define EL_MM_PACMAN_START             (EL_MM_START + 115)
-#define EL_MM_PACMAN_RIGHT             (EL_MM_PACMAN_START + 0)
-#define EL_MM_PACMAN_UP                        (EL_MM_PACMAN_START + 1)
-#define EL_MM_PACMAN_LEFT              (EL_MM_PACMAN_START + 2)
-#define EL_MM_PACMAN_DOWN              (EL_MM_PACMAN_START + 3)
-#define EL_MM_PACMAN_END               EL_MM_PACMAN_DOWN
-#define EL_MM_POLARIZER_START          (EL_MM_START + 119)
-#define EL_MM_POLARIZER_1              (EL_MM_POLARIZER_START + 0)
-#define EL_MM_POLARIZER_2              (EL_MM_POLARIZER_START + 1)
-#define EL_MM_POLARIZER_3              (EL_MM_POLARIZER_START + 2)
-#define EL_MM_POLARIZER_4              (EL_MM_POLARIZER_START + 3)
-#define EL_MM_POLARIZER_5              (EL_MM_POLARIZER_START + 4)
-#define EL_MM_POLARIZER_6              (EL_MM_POLARIZER_START + 5)
-#define EL_MM_POLARIZER_7              (EL_MM_POLARIZER_START + 6)
-#define EL_MM_POLARIZER_8              (EL_MM_POLARIZER_START + 7)
-#define EL_MM_POLARIZER_9              (EL_MM_POLARIZER_START + 8)
-#define EL_MM_POLARIZER_10             (EL_MM_POLARIZER_START + 9)
-#define EL_MM_POLARIZER_11             (EL_MM_POLARIZER_START + 10)
-#define EL_MM_POLARIZER_12             (EL_MM_POLARIZER_START + 11)
-#define EL_MM_POLARIZER_13             (EL_MM_POLARIZER_START + 12)
-#define EL_MM_POLARIZER_14             (EL_MM_POLARIZER_START + 13)
-#define EL_MM_POLARIZER_15             (EL_MM_POLARIZER_START + 14)
-#define EL_MM_POLARIZER_16             (EL_MM_POLARIZER_START + 15)
-#define EL_MM_POLARIZER_END            EL_MM_POLARIZER_15
-#define EL_MM_POLARIZER_CROSS_START    (EL_MM_START + 135)
-#define EL_MM_POLARIZER_CROSS_1                (EL_MM_POLARIZER_CROSS_START + 0)
-#define EL_MM_POLARIZER_CROSS_2                (EL_MM_POLARIZER_CROSS_START + 1)
-#define EL_MM_POLARIZER_CROSS_3                (EL_MM_POLARIZER_CROSS_START + 2)
-#define EL_MM_POLARIZER_CROSS_4                (EL_MM_POLARIZER_CROSS_START + 3)
-#define EL_MM_POLARIZER_CROSS_END      EL_MM_POLARIZER_CROSS_03
-#define EL_MM_MIRROR_FIXED_START       (EL_MM_START + 139)
-#define EL_MM_MIRROR_FIXED_1           (EL_MM_MIRROR_FIXED_START + 0)
-#define EL_MM_MIRROR_FIXED_2           (EL_MM_MIRROR_FIXED_START + 1)
-#define EL_MM_MIRROR_FIXED_3           (EL_MM_MIRROR_FIXED_START + 2)
-#define EL_MM_MIRROR_FIXED_4           (EL_MM_MIRROR_FIXED_START + 3)
-#define EL_MM_MIRROR_FIXED_END         EL_MM_MIRROR_FIXED_03
-#define EL_MM_STEEL_LOCK               (EL_MM_START + 143)
-#define EL_MM_KEY                      (EL_MM_START + 144)
-#define EL_MM_LIGHTBULB                        (EL_MM_START + 145)
-#define EL_MM_LIGHTBULB_ACTIVE         (EL_MM_START + 146)
-#define EL_MM_LIGHTBALL                        (EL_MM_START + 147)
-#define EL_MM_STEEL_BLOCK              (EL_MM_START + 148)
-#define EL_MM_WOODEN_LOCK              (EL_MM_START + 149)
-#define EL_MM_FUEL_FULL                        (EL_MM_START + 150)
-#define EL_MM_WOODEN_GRID_FIXED_START  (EL_MM_START + 151)
-#define EL_MM_WOODEN_GRID_FIXED_1      (EL_MM_WOODEN_GRID_FIXED_START + 0)
-#define EL_MM_WOODEN_GRID_FIXED_2      (EL_MM_WOODEN_GRID_FIXED_START + 1)
-#define EL_MM_WOODEN_GRID_FIXED_3      (EL_MM_WOODEN_GRID_FIXED_START + 2)
-#define EL_MM_WOODEN_GRID_FIXED_4      (EL_MM_WOODEN_GRID_FIXED_START + 3)
-#define EL_MM_WOODEN_GRID_FIXED_END    EL_MM_WOODEN_GRID_FIXED_03
-#define EL_MM_FUEL_EMPTY               (EL_MM_START + 155)
-
-#define EL_MM_UNUSED_156               (EL_MM_START + 156)
-#define EL_MM_UNUSED_157               (EL_MM_START + 157)
-#define EL_MM_UNUSED_158               (EL_MM_START + 158)
-#define EL_MM_UNUSED_159               (EL_MM_START + 159)
-
-#define EL_MM_END_1                    (EL_MM_START + 159)
-#define EL_MM_START_2                  (EL_MM_START + 160)
-
-#define EL_DF_START                    EL_MM_START_2
-#define EL_DF_START2                   (EL_DF_START - 240)
-
-#define EL_DF_MIRROR_START             EL_DF_START
-#define EL_DF_MIRROR_1                 (EL_DF_MIRROR_START + 0)
-#define EL_DF_MIRROR_2                 (EL_DF_MIRROR_START + 1)
-#define EL_DF_MIRROR_3                 (EL_DF_MIRROR_START + 2)
-#define EL_DF_MIRROR_4                 (EL_DF_MIRROR_START + 3)
-#define EL_DF_MIRROR_5                 (EL_DF_MIRROR_START + 4)
-#define EL_DF_MIRROR_6                 (EL_DF_MIRROR_START + 5)
-#define EL_DF_MIRROR_7                 (EL_DF_MIRROR_START + 6)
-#define EL_DF_MIRROR_8                 (EL_DF_MIRROR_START + 7)
-#define EL_DF_MIRROR_9                 (EL_DF_MIRROR_START + 8)
-#define EL_DF_MIRROR_10                        (EL_DF_MIRROR_START + 9)
-#define EL_DF_MIRROR_11                        (EL_DF_MIRROR_START + 10)
-#define EL_DF_MIRROR_12                        (EL_DF_MIRROR_START + 11)
-#define EL_DF_MIRROR_13                        (EL_DF_MIRROR_START + 12)
-#define EL_DF_MIRROR_14                        (EL_DF_MIRROR_START + 13)
-#define EL_DF_MIRROR_15                        (EL_DF_MIRROR_START + 14)
-#define EL_DF_MIRROR_16                        (EL_DF_MIRROR_START + 15)
-#define EL_DF_MIRROR_END               EL_DF_MIRROR_15
-
-#define EL_DF_WOODEN_GRID_FIXED_START  (EL_DF_START2 + 256)
-#define EL_DF_WOODEN_GRID_FIXED_1      (EL_DF_WOODEN_GRID_FIXED_START + 0)
-#define EL_DF_WOODEN_GRID_FIXED_2      (EL_DF_WOODEN_GRID_FIXED_START + 1)
-#define EL_DF_WOODEN_GRID_FIXED_3      (EL_DF_WOODEN_GRID_FIXED_START + 2)
-#define EL_DF_WOODEN_GRID_FIXED_4      (EL_DF_WOODEN_GRID_FIXED_START + 3)
-#define EL_DF_WOODEN_GRID_FIXED_5      (EL_DF_WOODEN_GRID_FIXED_START + 4)
-#define EL_DF_WOODEN_GRID_FIXED_6      (EL_DF_WOODEN_GRID_FIXED_START + 5)
-#define EL_DF_WOODEN_GRID_FIXED_7      (EL_DF_WOODEN_GRID_FIXED_START + 6)
-#define EL_DF_WOODEN_GRID_FIXED_8      (EL_DF_WOODEN_GRID_FIXED_START + 7)
-#define EL_DF_WOODEN_GRID_FIXED_END    EL_DF_WOODEN_GRID_FIXED_07
-
-#define EL_DF_STEEL_GRID_FIXED_START   (EL_DF_START2 + 264)
-#define EL_DF_STEEL_GRID_FIXED_1       (EL_DF_STEEL_GRID_FIXED_START + 0)
-#define EL_DF_STEEL_GRID_FIXED_2       (EL_DF_STEEL_GRID_FIXED_START + 1)
-#define EL_DF_STEEL_GRID_FIXED_3       (EL_DF_STEEL_GRID_FIXED_START + 2)
-#define EL_DF_STEEL_GRID_FIXED_4       (EL_DF_STEEL_GRID_FIXED_START + 3)
-#define EL_DF_STEEL_GRID_FIXED_5       (EL_DF_STEEL_GRID_FIXED_START + 4)
-#define EL_DF_STEEL_GRID_FIXED_6       (EL_DF_STEEL_GRID_FIXED_START + 5)
-#define EL_DF_STEEL_GRID_FIXED_7       (EL_DF_STEEL_GRID_FIXED_START + 6)
-#define EL_DF_STEEL_GRID_FIXED_8       (EL_DF_STEEL_GRID_FIXED_START + 7)
-#define EL_DF_STEEL_GRID_FIXED_END     EL_DF_STEEL_GRID_FIXED_07
-
-#define EL_DF_WOODEN_WALL_START                (EL_DF_START2 + 272)
-#define EL_DF_WOODEN_WALL_1            (EL_DF_WOODEN_WALL_START + 0)
-#define EL_DF_WOODEN_WALL_END          (EL_DF_WOODEN_WALL_START + 15)
-
-#define EL_DF_STEEL_WALL_START         (EL_DF_START2 + 288)
-#define EL_DF_STEEL_WALL_1             (EL_DF_STEEL_WALL_START + 0)
-#define EL_DF_STEEL_WALL_END           (EL_DF_STEEL_WALL_START + 15)
-
-#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_CELL                     (EL_DF_START2 + 305)
-#define EL_DF_MINE                     (EL_DF_START2 + 306)
-#define EL_DF_REFRACTOR                        (EL_DF_START2 + 307)
-
-#define EL_DF_LASER_START              (EL_DF_START2 + 308)
-#define EL_DF_LASER_RIGHT              (EL_DF_LASER_START + 0)
-#define EL_DF_LASER_UP                 (EL_DF_LASER_START + 1)
-#define EL_DF_LASER_LEFT               (EL_DF_LASER_START + 2)
-#define EL_DF_LASER_DOWN               (EL_DF_LASER_START + 3)
-#define EL_DF_LASER_END                        EL_DF_LASER_DOWN
-
-#define EL_DF_RECEIVER_START           (EL_DF_START2 + 312)
-#define EL_DF_RECEIVER_RIGHT           (EL_DF_RECEIVER_START + 0)
-#define EL_DF_RECEIVER_UP              (EL_DF_RECEIVER_START + 1)
-#define EL_DF_RECEIVER_LEFT            (EL_DF_RECEIVER_START + 2)
-#define EL_DF_RECEIVER_DOWN            (EL_DF_RECEIVER_START + 3)
-#define EL_DF_RECEIVER_END             EL_DF_RECEIVER_DOWN
-
-#define EL_DF_FIBRE_OPTIC_START                (EL_DF_START2 + 316)
-#define EL_DF_FIBRE_OPTIC_RED_1                (EL_DF_FIBRE_OPTIC_START + 0)
-#define EL_DF_FIBRE_OPTIC_RED_2                (EL_DF_FIBRE_OPTIC_START + 1)
-#define EL_DF_FIBRE_OPTIC_YELLOW_1     (EL_DF_FIBRE_OPTIC_START + 2)
-#define EL_DF_FIBRE_OPTIC_YELLOW_2     (EL_DF_FIBRE_OPTIC_START + 3)
-#define EL_DF_FIBRE_OPTIC_GREEN_1      (EL_DF_FIBRE_OPTIC_START + 4)
-#define EL_DF_FIBRE_OPTIC_GREEN_2      (EL_DF_FIBRE_OPTIC_START + 5)
-#define EL_DF_FIBRE_OPTIC_BLUE_1       (EL_DF_FIBRE_OPTIC_START + 6)
-#define EL_DF_FIBRE_OPTIC_BLUE_2       (EL_DF_FIBRE_OPTIC_START + 7)
-#define EL_DF_FIBRE_OPTIC_END          EL_DF_FIBRE_OPTIC_07
-
-#define EL_DF_MIRROR_ROTATING_START    (EL_DF_START2 + 324)
-#define EL_DF_MIRROR_ROTATING_1                (EL_DF_MIRROR_ROTATING_START + 0)
-#define EL_DF_MIRROR_ROTATING_2                (EL_DF_MIRROR_ROTATING_START + 1)
-#define EL_DF_MIRROR_ROTATING_3                (EL_DF_MIRROR_ROTATING_START + 2)
-#define EL_DF_MIRROR_ROTATING_4                (EL_DF_MIRROR_ROTATING_START + 3)
-#define EL_DF_MIRROR_ROTATING_5                (EL_DF_MIRROR_ROTATING_START + 4)
-#define EL_DF_MIRROR_ROTATING_6                (EL_DF_MIRROR_ROTATING_START + 5)
-#define EL_DF_MIRROR_ROTATING_7                (EL_DF_MIRROR_ROTATING_START + 6)
-#define EL_DF_MIRROR_ROTATING_8                (EL_DF_MIRROR_ROTATING_START + 7)
-#define EL_DF_MIRROR_ROTATING_9                (EL_DF_MIRROR_ROTATING_START + 8)
-#define EL_DF_MIRROR_ROTATING_10       (EL_DF_MIRROR_ROTATING_START + 9)
-#define EL_DF_MIRROR_ROTATING_11       (EL_DF_MIRROR_ROTATING_START + 10)
-#define EL_DF_MIRROR_ROTATING_12       (EL_DF_MIRROR_ROTATING_START + 11)
-#define EL_DF_MIRROR_ROTATING_13       (EL_DF_MIRROR_ROTATING_START + 12)
-#define EL_DF_MIRROR_ROTATING_14       (EL_DF_MIRROR_ROTATING_START + 13)
-#define EL_DF_MIRROR_ROTATING_15       (EL_DF_MIRROR_ROTATING_START + 14)
-#define EL_DF_MIRROR_ROTATING_16       (EL_DF_MIRROR_ROTATING_START + 15)
-#define EL_DF_MIRROR_ROTATING_END      EL_DF_MIRROR_ROTATING_15
-
-#define EL_DF_WOODEN_GRID_ROTATING_START (EL_DF_START2 + 340)
-#define EL_DF_WOODEN_GRID_ROTATING_1   (EL_DF_WOODEN_GRID_ROTATING_START + 0)
-#define EL_DF_WOODEN_GRID_ROTATING_2   (EL_DF_WOODEN_GRID_ROTATING_START + 1)
-#define EL_DF_WOODEN_GRID_ROTATING_3   (EL_DF_WOODEN_GRID_ROTATING_START + 2)
-#define EL_DF_WOODEN_GRID_ROTATING_4   (EL_DF_WOODEN_GRID_ROTATING_START + 3)
-#define EL_DF_WOODEN_GRID_ROTATING_5   (EL_DF_WOODEN_GRID_ROTATING_START + 4)
-#define EL_DF_WOODEN_GRID_ROTATING_6   (EL_DF_WOODEN_GRID_ROTATING_START + 5)
-#define EL_DF_WOODEN_GRID_ROTATING_7   (EL_DF_WOODEN_GRID_ROTATING_START + 6)
-#define EL_DF_WOODEN_GRID_ROTATING_8   (EL_DF_WOODEN_GRID_ROTATING_START + 7)
-#define EL_DF_WOODEN_GRID_ROTATING_END EL_DF_WOODEN_GRID_ROTATING_07
-
-#define EL_DF_STEEL_GRID_ROTATING_START        (EL_DF_START2 + 348)
-#define EL_DF_STEEL_GRID_ROTATING_1    (EL_DF_STEEL_GRID_ROTATING_START + 0)
-#define EL_DF_STEEL_GRID_ROTATING_2    (EL_DF_STEEL_GRID_ROTATING_START + 1)
-#define EL_DF_STEEL_GRID_ROTATING_3    (EL_DF_STEEL_GRID_ROTATING_START + 2)
-#define EL_DF_STEEL_GRID_ROTATING_4    (EL_DF_STEEL_GRID_ROTATING_START + 3)
-#define EL_DF_STEEL_GRID_ROTATING_5    (EL_DF_STEEL_GRID_ROTATING_START + 4)
-#define EL_DF_STEEL_GRID_ROTATING_6    (EL_DF_STEEL_GRID_ROTATING_START + 5)
-#define EL_DF_STEEL_GRID_ROTATING_7    (EL_DF_STEEL_GRID_ROTATING_START + 6)
-#define EL_DF_STEEL_GRID_ROTATING_8    (EL_DF_STEEL_GRID_ROTATING_START + 7)
-#define EL_DF_STEEL_GRID_ROTATING_END  EL_DF_STEEL_GRID_ROTATING_07
-
-#define EL_DF_END                      (EL_DF_START2 + 355)
-
-#define EL_MM_TELEPORTER_RED_START     (EL_DF_START2 + 356)
-#define EL_MM_TELEPORTER_RED_1         (EL_MM_TELEPORTER_RED_START + 0)
-#define EL_MM_TELEPORTER_RED_2         (EL_MM_TELEPORTER_RED_START + 1)
-#define EL_MM_TELEPORTER_RED_3         (EL_MM_TELEPORTER_RED_START + 2)
-#define EL_MM_TELEPORTER_RED_4         (EL_MM_TELEPORTER_RED_START + 3)
-#define EL_MM_TELEPORTER_RED_5         (EL_MM_TELEPORTER_RED_START + 4)
-#define EL_MM_TELEPORTER_RED_6         (EL_MM_TELEPORTER_RED_START + 5)
-#define EL_MM_TELEPORTER_RED_7         (EL_MM_TELEPORTER_RED_START + 6)
-#define EL_MM_TELEPORTER_RED_8         (EL_MM_TELEPORTER_RED_START + 7)
-#define EL_MM_TELEPORTER_RED_9         (EL_MM_TELEPORTER_RED_START + 8)
-#define EL_MM_TELEPORTER_RED_10                (EL_MM_TELEPORTER_RED_START + 9)
-#define EL_MM_TELEPORTER_RED_11                (EL_MM_TELEPORTER_RED_START + 10)
-#define EL_MM_TELEPORTER_RED_12                (EL_MM_TELEPORTER_RED_START + 11)
-#define EL_MM_TELEPORTER_RED_13                (EL_MM_TELEPORTER_RED_START + 12)
-#define EL_MM_TELEPORTER_RED_14                (EL_MM_TELEPORTER_RED_START + 13)
-#define EL_MM_TELEPORTER_RED_15                (EL_MM_TELEPORTER_RED_START + 14)
-#define EL_MM_TELEPORTER_RED_16                (EL_MM_TELEPORTER_RED_START + 15)
-#define EL_MM_TELEPORTER_RED_END       EL_MM_TELEPORTER_RED_16
-#define EL_MM_TELEPORTER_YELLOW_START  (EL_DF_START2 + 372)
-#define EL_MM_TELEPORTER_YELLOW_1      (EL_MM_TELEPORTER_YELLOW_START + 0)
-#define EL_MM_TELEPORTER_YELLOW_2      (EL_MM_TELEPORTER_YELLOW_START + 1)
-#define EL_MM_TELEPORTER_YELLOW_3      (EL_MM_TELEPORTER_YELLOW_START + 2)
-#define EL_MM_TELEPORTER_YELLOW_4      (EL_MM_TELEPORTER_YELLOW_START + 3)
-#define EL_MM_TELEPORTER_YELLOW_5      (EL_MM_TELEPORTER_YELLOW_START + 4)
-#define EL_MM_TELEPORTER_YELLOW_6      (EL_MM_TELEPORTER_YELLOW_START + 5)
-#define EL_MM_TELEPORTER_YELLOW_7      (EL_MM_TELEPORTER_YELLOW_START + 6)
-#define EL_MM_TELEPORTER_YELLOW_8      (EL_MM_TELEPORTER_YELLOW_START + 7)
-#define EL_MM_TELEPORTER_YELLOW_9      (EL_MM_TELEPORTER_YELLOW_START + 8)
-#define EL_MM_TELEPORTER_YELLOW_10     (EL_MM_TELEPORTER_YELLOW_START + 9)
-#define EL_MM_TELEPORTER_YELLOW_11     (EL_MM_TELEPORTER_YELLOW_START + 10)
-#define EL_MM_TELEPORTER_YELLOW_12     (EL_MM_TELEPORTER_YELLOW_START + 11)
-#define EL_MM_TELEPORTER_YELLOW_13     (EL_MM_TELEPORTER_YELLOW_START + 12)
-#define EL_MM_TELEPORTER_YELLOW_14     (EL_MM_TELEPORTER_YELLOW_START + 13)
-#define EL_MM_TELEPORTER_YELLOW_15     (EL_MM_TELEPORTER_YELLOW_START + 14)
-#define EL_MM_TELEPORTER_YELLOW_16     (EL_MM_TELEPORTER_YELLOW_START + 15)
-#define EL_MM_TELEPORTER_YELLOW_END    EL_MM_TELEPORTER_YELLOW_16
-#define EL_MM_TELEPORTER_GREEN_START   (EL_DF_START2 + 388)
-#define EL_MM_TELEPORTER_GREEN_1       (EL_MM_TELEPORTER_GREEN_START + 0)
-#define EL_MM_TELEPORTER_GREEN_2       (EL_MM_TELEPORTER_GREEN_START + 1)
-#define EL_MM_TELEPORTER_GREEN_3       (EL_MM_TELEPORTER_GREEN_START + 2)
-#define EL_MM_TELEPORTER_GREEN_4       (EL_MM_TELEPORTER_GREEN_START + 3)
-#define EL_MM_TELEPORTER_GREEN_5       (EL_MM_TELEPORTER_GREEN_START + 4)
-#define EL_MM_TELEPORTER_GREEN_6       (EL_MM_TELEPORTER_GREEN_START + 5)
-#define EL_MM_TELEPORTER_GREEN_7       (EL_MM_TELEPORTER_GREEN_START + 6)
-#define EL_MM_TELEPORTER_GREEN_8       (EL_MM_TELEPORTER_GREEN_START + 7)
-#define EL_MM_TELEPORTER_GREEN_9       (EL_MM_TELEPORTER_GREEN_START + 8)
-#define EL_MM_TELEPORTER_GREEN_10      (EL_MM_TELEPORTER_GREEN_START + 9)
-#define EL_MM_TELEPORTER_GREEN_11      (EL_MM_TELEPORTER_GREEN_START + 10)
-#define EL_MM_TELEPORTER_GREEN_12      (EL_MM_TELEPORTER_GREEN_START + 11)
-#define EL_MM_TELEPORTER_GREEN_13      (EL_MM_TELEPORTER_GREEN_START + 12)
-#define EL_MM_TELEPORTER_GREEN_14      (EL_MM_TELEPORTER_GREEN_START + 13)
-#define EL_MM_TELEPORTER_GREEN_15      (EL_MM_TELEPORTER_GREEN_START + 14)
-#define EL_MM_TELEPORTER_GREEN_16      (EL_MM_TELEPORTER_GREEN_START + 15)
-#define EL_MM_TELEPORTER_GREEN_END     EL_MM_TELEPORTER_GREEN_16
-#define EL_MM_TELEPORTER_BLUE_START    (EL_DF_START2 + 404)
-#define EL_MM_TELEPORTER_BLUE_1                (EL_MM_TELEPORTER_BLUE_START + 0)
-#define EL_MM_TELEPORTER_BLUE_2                (EL_MM_TELEPORTER_BLUE_START + 1)
-#define EL_MM_TELEPORTER_BLUE_3                (EL_MM_TELEPORTER_BLUE_START + 2)
-#define EL_MM_TELEPORTER_BLUE_4                (EL_MM_TELEPORTER_BLUE_START + 3)
-#define EL_MM_TELEPORTER_BLUE_5                (EL_MM_TELEPORTER_BLUE_START + 4)
-#define EL_MM_TELEPORTER_BLUE_6                (EL_MM_TELEPORTER_BLUE_START + 5)
-#define EL_MM_TELEPORTER_BLUE_7                (EL_MM_TELEPORTER_BLUE_START + 6)
-#define EL_MM_TELEPORTER_BLUE_8                (EL_MM_TELEPORTER_BLUE_START + 7)
-#define EL_MM_TELEPORTER_BLUE_9                (EL_MM_TELEPORTER_BLUE_START + 8)
-#define EL_MM_TELEPORTER_BLUE_10       (EL_MM_TELEPORTER_BLUE_START + 9)
-#define EL_MM_TELEPORTER_BLUE_11       (EL_MM_TELEPORTER_BLUE_START + 10)
-#define EL_MM_TELEPORTER_BLUE_12       (EL_MM_TELEPORTER_BLUE_START + 11)
-#define EL_MM_TELEPORTER_BLUE_13       (EL_MM_TELEPORTER_BLUE_START + 12)
-#define EL_MM_TELEPORTER_BLUE_14       (EL_MM_TELEPORTER_BLUE_START + 13)
-#define EL_MM_TELEPORTER_BLUE_15       (EL_MM_TELEPORTER_BLUE_START + 14)
-#define EL_MM_TELEPORTER_BLUE_16       (EL_MM_TELEPORTER_BLUE_START + 15)
-#define EL_MM_TELEPORTER_BLUE_END      EL_MM_TELEPORTER_BLUE_16
-
-#define EL_MM_MCDUFFIN                 1204
-#define EL_MM_PACMAN                   1205
-#define EL_MM_FUSE                     1206
-#define EL_MM_STEEL_WALL               1207
-#define EL_MM_WOODEN_WALL              1208
-#define EL_MM_ICE_WALL                 1209
-#define EL_MM_AMOEBA_WALL              1210
-#define EL_DF_LASER                    1211
-#define EL_DF_RECEIVER                 1212
-#define EL_DF_STEEL_WALL               1213
-#define EL_DF_WOODEN_WALL              1214
-
-#define EL_MM_END_2                    (EL_DF_START2 + 430)
-#define EL_MM_END                      EL_MM_END_2
-
-#define EL_SPRING_LEFT                 1215
-#define EL_SPRING_RIGHT                        1216
-
-#define NUM_FILE_ELEMENTS              1217
+#define EL_STEEL_CHAR_ASCII0_END               (EL_STEEL_CHAR_ASCII0 + 111)
+#define EL_STEEL_CHAR_END                      (EL_STEEL_CHAR_START  + 79)
+
+#define EL_STEEL_CHAR(c)                       (EL_STEEL_CHAR_ASCII0+MAP_FONT_ASCII(c))
+
+// unused elements
+#define EL_SPERMS                              812
+#define EL_BULLET                              813
+#define EL_HEART                               814
+#define EL_CROSS                               815
+#define EL_FRANKIE                             816
+#define EL_SIGN_SPERMS                         817
+#define EL_SIGN_BULLET                         818
+#define EL_SIGN_HEART                          819
+#define EL_SIGN_CROSS                          820
+#define EL_SIGN_FRANKIE                                821
+
+// DC2 style elements
+#define EL_STEEL_EXIT_CLOSED                   822
+#define EL_STEEL_EXIT_OPEN                     823
+
+#define EL_DC_STEELWALL_1_LEFT                 824
+#define EL_DC_STEELWALL_1_RIGHT                        825
+#define EL_DC_STEELWALL_1_TOP                  826
+#define EL_DC_STEELWALL_1_BOTTOM               827
+#define EL_DC_STEELWALL_1_HORIZONTAL           828
+#define EL_DC_STEELWALL_1_VERTICAL             829
+#define EL_DC_STEELWALL_1_TOPLEFT              830
+#define EL_DC_STEELWALL_1_TOPRIGHT             831
+#define EL_DC_STEELWALL_1_BOTTOMLEFT           832
+#define EL_DC_STEELWALL_1_BOTTOMRIGHT          833
+#define EL_DC_STEELWALL_1_TOPLEFT_2            834
+#define EL_DC_STEELWALL_1_TOPRIGHT_2           835
+#define EL_DC_STEELWALL_1_BOTTOMLEFT_2         836
+#define EL_DC_STEELWALL_1_BOTTOMRIGHT_2                837
+
+#define EL_DC_STEELWALL_2_LEFT                 838
+#define EL_DC_STEELWALL_2_RIGHT                        839
+#define EL_DC_STEELWALL_2_TOP                  840
+#define EL_DC_STEELWALL_2_BOTTOM               841
+#define EL_DC_STEELWALL_2_HORIZONTAL           842
+#define EL_DC_STEELWALL_2_VERTICAL             843
+#define EL_DC_STEELWALL_2_MIDDLE               844
+#define EL_DC_STEELWALL_2_SINGLE               845
+
+#define EL_DC_SWITCHGATE_SWITCH_UP             846
+#define EL_DC_SWITCHGATE_SWITCH_DOWN           847
+#define EL_DC_TIMEGATE_SWITCH                  848
+#define EL_DC_TIMEGATE_SWITCH_ACTIVE           849
+
+#define EL_DC_LANDMINE                         850
+
+#define EL_EXPANDABLE_STEELWALL                        851
+#define EL_EXPANDABLE_STEELWALL_HORIZONTAL     852
+#define EL_EXPANDABLE_STEELWALL_VERTICAL       853
+#define EL_EXPANDABLE_STEELWALL_ANY            854
+
+#define EL_EM_EXIT_CLOSED                      855
+#define EL_EM_EXIT_OPEN                                856
+#define EL_EM_STEEL_EXIT_CLOSED                        857
+#define EL_EM_STEEL_EXIT_OPEN                  858
+
+#define EL_DC_GATE_FAKE_GRAY                   859
+
+#define EL_DC_MAGIC_WALL                       860
+
+#define EL_QUICKSAND_FAST_EMPTY                        861
+#define EL_QUICKSAND_FAST_FULL                 862
+
+#define EL_FROM_LEVEL_TEMPLATE                 863
+
+// MM style elements
+#define EL_MM_START                            864
+#define EL_MM_START_1                          EL_MM_START
+
+#define EL_MM_EMPTY_SPACE                      (EL_MM_START + 0)
+#define EL_MM_EMPTY                            EL_MM_EMPTY_SPACE
+#define EL_MM_MIRROR_START                     (EL_MM_START + 1)
+#define EL_MM_MIRROR_1                         (EL_MM_MIRROR_START + 0)
+#define EL_MM_MIRROR_2                         (EL_MM_MIRROR_START + 1)
+#define EL_MM_MIRROR_3                         (EL_MM_MIRROR_START + 2)
+#define EL_MM_MIRROR_4                         (EL_MM_MIRROR_START + 3)
+#define EL_MM_MIRROR_5                         (EL_MM_MIRROR_START + 4)
+#define EL_MM_MIRROR_6                         (EL_MM_MIRROR_START + 5)
+#define EL_MM_MIRROR_7                         (EL_MM_MIRROR_START + 6)
+#define EL_MM_MIRROR_8                         (EL_MM_MIRROR_START + 7)
+#define EL_MM_MIRROR_9                         (EL_MM_MIRROR_START + 8)
+#define EL_MM_MIRROR_10                                (EL_MM_MIRROR_START + 9)
+#define EL_MM_MIRROR_11                                (EL_MM_MIRROR_START + 10)
+#define EL_MM_MIRROR_12                                (EL_MM_MIRROR_START + 11)
+#define EL_MM_MIRROR_13                                (EL_MM_MIRROR_START + 12)
+#define EL_MM_MIRROR_14                                (EL_MM_MIRROR_START + 13)
+#define EL_MM_MIRROR_15                                (EL_MM_MIRROR_START + 14)
+#define EL_MM_MIRROR_16                                (EL_MM_MIRROR_START + 15)
+#define EL_MM_MIRROR_END                       EL_MM_MIRROR_15
+#define EL_MM_STEEL_GRID_FIXED_START           (EL_MM_START + 17)
+#define EL_MM_STEEL_GRID_FIXED_1               (EL_MM_STEEL_GRID_FIXED_START + 0)
+#define EL_MM_STEEL_GRID_FIXED_2               (EL_MM_STEEL_GRID_FIXED_START + 1)
+#define EL_MM_STEEL_GRID_FIXED_3               (EL_MM_STEEL_GRID_FIXED_START + 2)
+#define EL_MM_STEEL_GRID_FIXED_4               (EL_MM_STEEL_GRID_FIXED_START + 3)
+#define EL_MM_STEEL_GRID_FIXED_END             EL_MM_STEEL_GRID_FIXED_03
+#define EL_MM_MCDUFFIN_START                   (EL_MM_START + 21)
+#define EL_MM_MCDUFFIN_RIGHT                   (EL_MM_MCDUFFIN_START + 0)
+#define EL_MM_MCDUFFIN_UP                      (EL_MM_MCDUFFIN_START + 1)
+#define EL_MM_MCDUFFIN_LEFT                    (EL_MM_MCDUFFIN_START + 2)
+#define EL_MM_MCDUFFIN_DOWN                    (EL_MM_MCDUFFIN_START + 3)
+#define EL_MM_MCDUFFIN_END                     EL_MM_MCDUFFIN_DOWN
+#define EL_MM_EXIT_CLOSED                      (EL_MM_START + 25)
+#define EL_MM_EXIT_OPENING_1                   (EL_MM_START + 26)
+#define EL_MM_EXIT_OPENING_2                   (EL_MM_START + 27)
+#define EL_MM_EXIT_OPEN                                (EL_MM_START + 28)
+#define EL_MM_KETTLE                           (EL_MM_START + 29)
+#define EL_MM_BOMB                             (EL_MM_START + 30)
+#define EL_MM_PRISM                            (EL_MM_START + 31)
+#define EL_MM_WALL_START                       (EL_MM_START + 32)
+#define EL_MM_WALL_EMPTY                       EL_MM_WALL_START
+#define EL_MM_WALL_00                          EL_MM_WALL_START
+#define EL_MM_STEEL_WALL_START                 EL_MM_WALL_00
+#define EL_MM_STEEL_WALL_1                     EL_MM_STEEL_WALL_START
+#define EL_MM_WALL_15                          (EL_MM_START + 47)
+#define EL_MM_STEEL_WALL_END                   EL_MM_WALL_15
+#define EL_MM_WALL_16                          (EL_MM_START + 48)
+#define EL_MM_WOODEN_WALL_START                        EL_MM_WALL_16
+#define EL_MM_WOODEN_WALL_1                    EL_MM_WOODEN_WALL_START
+#define EL_MM_WALL_31                          (EL_MM_START + 63)
+#define EL_MM_WOODEN_WALL_END                  EL_MM_WALL_31
+#define EL_MM_WALL_32                          (EL_MM_START + 64)
+#define EL_MM_ICE_WALL_START                   EL_MM_WALL_32
+#define EL_MM_ICE_WALL_1                       EL_MM_ICE_WALL_START
+#define EL_MM_WALL_47                          (EL_MM_START + 79)
+#define EL_MM_ICE_WALL_END                     EL_MM_WALL_47
+#define EL_MM_WALL_48                          (EL_MM_START + 80)
+#define EL_MM_AMOEBA_WALL_START                        EL_MM_WALL_48
+#define EL_MM_AMOEBA_WALL_1                    EL_MM_AMOEBA_WALL_START
+#define EL_MM_WALL_63                          (EL_MM_START + 95)
+#define EL_MM_AMOEBA_WALL_END                  EL_MM_WALL_63
+#define EL_MM_WALL_END                         EL_MM_WALL_63
+#define EL_MM_WOODEN_BLOCK                     (EL_MM_START + 96)
+#define EL_MM_GRAY_BALL                                (EL_MM_START + 97)
+#define EL_MM_TELEPORTER_START                 (EL_MM_START + 98)
+#define EL_MM_TELEPORTER_1                     (EL_MM_TELEPORTER_START + 0)
+#define EL_MM_TELEPORTER_2                     (EL_MM_TELEPORTER_START + 1)
+#define EL_MM_TELEPORTER_3                     (EL_MM_TELEPORTER_START + 2)
+#define EL_MM_TELEPORTER_4                     (EL_MM_TELEPORTER_START + 3)
+#define EL_MM_TELEPORTER_5                     (EL_MM_TELEPORTER_START + 4)
+#define EL_MM_TELEPORTER_6                     (EL_MM_TELEPORTER_START + 5)
+#define EL_MM_TELEPORTER_7                     (EL_MM_TELEPORTER_START + 6)
+#define EL_MM_TELEPORTER_8                     (EL_MM_TELEPORTER_START + 7)
+#define EL_MM_TELEPORTER_9                     (EL_MM_TELEPORTER_START + 8)
+#define EL_MM_TELEPORTER_10                    (EL_MM_TELEPORTER_START + 9)
+#define EL_MM_TELEPORTER_11                    (EL_MM_TELEPORTER_START + 10)
+#define EL_MM_TELEPORTER_12                    (EL_MM_TELEPORTER_START + 11)
+#define EL_MM_TELEPORTER_13                    (EL_MM_TELEPORTER_START + 12)
+#define EL_MM_TELEPORTER_14                    (EL_MM_TELEPORTER_START + 13)
+#define EL_MM_TELEPORTER_15                    (EL_MM_TELEPORTER_START + 14)
+#define EL_MM_TELEPORTER_16                    (EL_MM_TELEPORTER_START + 15)
+#define EL_MM_TELEPORTER_END                   EL_MM_TELEPORTER_15
+#define EL_MM_FUSE_ACTIVE                      (EL_MM_START + 114)
+#define EL_MM_PACMAN_START                     (EL_MM_START + 115)
+#define EL_MM_PACMAN_RIGHT                     (EL_MM_PACMAN_START + 0)
+#define EL_MM_PACMAN_UP                                (EL_MM_PACMAN_START + 1)
+#define EL_MM_PACMAN_LEFT                      (EL_MM_PACMAN_START + 2)
+#define EL_MM_PACMAN_DOWN                      (EL_MM_PACMAN_START + 3)
+#define EL_MM_PACMAN_END                       EL_MM_PACMAN_DOWN
+#define EL_MM_POLARIZER_START                  (EL_MM_START + 119)
+#define EL_MM_POLARIZER_1                      (EL_MM_POLARIZER_START + 0)
+#define EL_MM_POLARIZER_2                      (EL_MM_POLARIZER_START + 1)
+#define EL_MM_POLARIZER_3                      (EL_MM_POLARIZER_START + 2)
+#define EL_MM_POLARIZER_4                      (EL_MM_POLARIZER_START + 3)
+#define EL_MM_POLARIZER_5                      (EL_MM_POLARIZER_START + 4)
+#define EL_MM_POLARIZER_6                      (EL_MM_POLARIZER_START + 5)
+#define EL_MM_POLARIZER_7                      (EL_MM_POLARIZER_START + 6)
+#define EL_MM_POLARIZER_8                      (EL_MM_POLARIZER_START + 7)
+#define EL_MM_POLARIZER_9                      (EL_MM_POLARIZER_START + 8)
+#define EL_MM_POLARIZER_10                     (EL_MM_POLARIZER_START + 9)
+#define EL_MM_POLARIZER_11                     (EL_MM_POLARIZER_START + 10)
+#define EL_MM_POLARIZER_12                     (EL_MM_POLARIZER_START + 11)
+#define EL_MM_POLARIZER_13                     (EL_MM_POLARIZER_START + 12)
+#define EL_MM_POLARIZER_14                     (EL_MM_POLARIZER_START + 13)
+#define EL_MM_POLARIZER_15                     (EL_MM_POLARIZER_START + 14)
+#define EL_MM_POLARIZER_16                     (EL_MM_POLARIZER_START + 15)
+#define EL_MM_POLARIZER_END                    EL_MM_POLARIZER_15
+#define EL_MM_POLARIZER_CROSS_START            (EL_MM_START + 135)
+#define EL_MM_POLARIZER_CROSS_1                        (EL_MM_POLARIZER_CROSS_START + 0)
+#define EL_MM_POLARIZER_CROSS_2                        (EL_MM_POLARIZER_CROSS_START + 1)
+#define EL_MM_POLARIZER_CROSS_3                        (EL_MM_POLARIZER_CROSS_START + 2)
+#define EL_MM_POLARIZER_CROSS_4                        (EL_MM_POLARIZER_CROSS_START + 3)
+#define EL_MM_POLARIZER_CROSS_END              EL_MM_POLARIZER_CROSS_03
+#define EL_MM_MIRROR_FIXED_START               (EL_MM_START + 139)
+#define EL_MM_MIRROR_FIXED_1                   (EL_MM_MIRROR_FIXED_START + 0)
+#define EL_MM_MIRROR_FIXED_2                   (EL_MM_MIRROR_FIXED_START + 1)
+#define EL_MM_MIRROR_FIXED_3                   (EL_MM_MIRROR_FIXED_START + 2)
+#define EL_MM_MIRROR_FIXED_4                   (EL_MM_MIRROR_FIXED_START + 3)
+#define EL_MM_MIRROR_FIXED_END                 EL_MM_MIRROR_FIXED_03
+#define EL_MM_STEEL_LOCK                       (EL_MM_START + 143)
+#define EL_MM_KEY                              (EL_MM_START + 144)
+#define EL_MM_LIGHTBULB                                (EL_MM_START + 145)
+#define EL_MM_LIGHTBULB_ACTIVE                 (EL_MM_START + 146)
+#define EL_MM_LIGHTBALL                                (EL_MM_START + 147)
+#define EL_MM_STEEL_BLOCK                      (EL_MM_START + 148)
+#define EL_MM_WOODEN_LOCK                      (EL_MM_START + 149)
+#define EL_MM_FUEL_FULL                                (EL_MM_START + 150)
+#define EL_MM_WOODEN_GRID_FIXED_START          (EL_MM_START + 151)
+#define EL_MM_WOODEN_GRID_FIXED_1              (EL_MM_WOODEN_GRID_FIXED_START + 0)
+#define EL_MM_WOODEN_GRID_FIXED_2              (EL_MM_WOODEN_GRID_FIXED_START + 1)
+#define EL_MM_WOODEN_GRID_FIXED_3              (EL_MM_WOODEN_GRID_FIXED_START + 2)
+#define EL_MM_WOODEN_GRID_FIXED_4              (EL_MM_WOODEN_GRID_FIXED_START + 3)
+#define EL_MM_WOODEN_GRID_FIXED_END            EL_MM_WOODEN_GRID_FIXED_03
+#define EL_MM_FUEL_EMPTY                       (EL_MM_START + 155)
+#define EL_MM_ENVELOPE_1                       (EL_MM_START + 156)
+#define EL_MM_ENVELOPE_2                       (EL_MM_START + 157)
+#define EL_MM_ENVELOPE_3                       (EL_MM_START + 158)
+#define EL_MM_ENVELOPE_4                       (EL_MM_START + 159)
+
+#define EL_MM_END_1                            (EL_MM_START + 159)
+#define EL_MM_START_2                          (EL_MM_START + 160)
+
+// DF style elements
+#define EL_DF_START                            EL_MM_START_2
+#define EL_DF_START_1                          EL_MM_START_2
+#define EL_DF_START2                           (EL_DF_START - 240)
+
+#define EL_DF_MIRROR_START                     EL_DF_START
+#define EL_DF_MIRROR_1                         (EL_DF_MIRROR_START + 0)
+#define EL_DF_MIRROR_2                         (EL_DF_MIRROR_START + 1)
+#define EL_DF_MIRROR_3                         (EL_DF_MIRROR_START + 2)
+#define EL_DF_MIRROR_4                         (EL_DF_MIRROR_START + 3)
+#define EL_DF_MIRROR_5                         (EL_DF_MIRROR_START + 4)
+#define EL_DF_MIRROR_6                         (EL_DF_MIRROR_START + 5)
+#define EL_DF_MIRROR_7                         (EL_DF_MIRROR_START + 6)
+#define EL_DF_MIRROR_8                         (EL_DF_MIRROR_START + 7)
+#define EL_DF_MIRROR_9                         (EL_DF_MIRROR_START + 8)
+#define EL_DF_MIRROR_10                                (EL_DF_MIRROR_START + 9)
+#define EL_DF_MIRROR_11                                (EL_DF_MIRROR_START + 10)
+#define EL_DF_MIRROR_12                                (EL_DF_MIRROR_START + 11)
+#define EL_DF_MIRROR_13                                (EL_DF_MIRROR_START + 12)
+#define EL_DF_MIRROR_14                                (EL_DF_MIRROR_START + 13)
+#define EL_DF_MIRROR_15                                (EL_DF_MIRROR_START + 14)
+#define EL_DF_MIRROR_16                                (EL_DF_MIRROR_START + 15)
+#define EL_DF_MIRROR_END                       EL_DF_MIRROR_15
+
+#define EL_DF_WOODEN_GRID_FIXED_START          (EL_DF_START2 + 256)
+#define EL_DF_WOODEN_GRID_FIXED_1              (EL_DF_WOODEN_GRID_FIXED_START + 0)
+#define EL_DF_WOODEN_GRID_FIXED_2              (EL_DF_WOODEN_GRID_FIXED_START + 1)
+#define EL_DF_WOODEN_GRID_FIXED_3              (EL_DF_WOODEN_GRID_FIXED_START + 2)
+#define EL_DF_WOODEN_GRID_FIXED_4              (EL_DF_WOODEN_GRID_FIXED_START + 3)
+#define EL_DF_WOODEN_GRID_FIXED_5              (EL_DF_WOODEN_GRID_FIXED_START + 4)
+#define EL_DF_WOODEN_GRID_FIXED_6              (EL_DF_WOODEN_GRID_FIXED_START + 5)
+#define EL_DF_WOODEN_GRID_FIXED_7              (EL_DF_WOODEN_GRID_FIXED_START + 6)
+#define EL_DF_WOODEN_GRID_FIXED_8              (EL_DF_WOODEN_GRID_FIXED_START + 7)
+#define EL_DF_WOODEN_GRID_FIXED_END            EL_DF_WOODEN_GRID_FIXED_07
+
+#define EL_DF_STEEL_GRID_FIXED_START           (EL_DF_START2 + 264)
+#define EL_DF_STEEL_GRID_FIXED_1               (EL_DF_STEEL_GRID_FIXED_START + 0)
+#define EL_DF_STEEL_GRID_FIXED_2               (EL_DF_STEEL_GRID_FIXED_START + 1)
+#define EL_DF_STEEL_GRID_FIXED_3               (EL_DF_STEEL_GRID_FIXED_START + 2)
+#define EL_DF_STEEL_GRID_FIXED_4               (EL_DF_STEEL_GRID_FIXED_START + 3)
+#define EL_DF_STEEL_GRID_FIXED_5               (EL_DF_STEEL_GRID_FIXED_START + 4)
+#define EL_DF_STEEL_GRID_FIXED_6               (EL_DF_STEEL_GRID_FIXED_START + 5)
+#define EL_DF_STEEL_GRID_FIXED_7               (EL_DF_STEEL_GRID_FIXED_START + 6)
+#define EL_DF_STEEL_GRID_FIXED_8               (EL_DF_STEEL_GRID_FIXED_START + 7)
+#define EL_DF_STEEL_GRID_FIXED_END             EL_DF_STEEL_GRID_FIXED_07
+
+#define EL_DF_WOODEN_WALL_START                        (EL_DF_START2 + 272)
+#define EL_DF_WOODEN_WALL_1                    (EL_DF_WOODEN_WALL_START + 0)
+#define EL_DF_WOODEN_WALL_END                  (EL_DF_WOODEN_WALL_START + 15)
+
+#define EL_DF_STEEL_WALL_START                 (EL_DF_START2 + 288)
+#define EL_DF_STEEL_WALL_1                     (EL_DF_STEEL_WALL_START + 0)
+#define EL_DF_STEEL_WALL_END                   (EL_DF_STEEL_WALL_START + 15)
+
+#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_CELL                             (EL_DF_START2 + 305)
+#define EL_DF_MINE                             (EL_DF_START2 + 306)
+#define EL_DF_REFRACTOR                                (EL_DF_START2 + 307)
+
+#define EL_DF_LASER_START                      (EL_DF_START2 + 308)
+#define EL_DF_LASER_RIGHT                      (EL_DF_LASER_START + 0)
+#define EL_DF_LASER_UP                         (EL_DF_LASER_START + 1)
+#define EL_DF_LASER_LEFT                       (EL_DF_LASER_START + 2)
+#define EL_DF_LASER_DOWN                       (EL_DF_LASER_START + 3)
+#define EL_DF_LASER_END                                EL_DF_LASER_DOWN
+
+#define EL_DF_RECEIVER_START                   (EL_DF_START2 + 312)
+#define EL_DF_RECEIVER_RIGHT                   (EL_DF_RECEIVER_START + 0)
+#define EL_DF_RECEIVER_UP                      (EL_DF_RECEIVER_START + 1)
+#define EL_DF_RECEIVER_LEFT                    (EL_DF_RECEIVER_START + 2)
+#define EL_DF_RECEIVER_DOWN                    (EL_DF_RECEIVER_START + 3)
+#define EL_DF_RECEIVER_END                     EL_DF_RECEIVER_DOWN
+
+#define EL_DF_FIBRE_OPTIC_START                        (EL_DF_START2 + 316)
+#define EL_DF_FIBRE_OPTIC_RED_1                        (EL_DF_FIBRE_OPTIC_START + 0)
+#define EL_DF_FIBRE_OPTIC_RED_2                        (EL_DF_FIBRE_OPTIC_START + 1)
+#define EL_DF_FIBRE_OPTIC_YELLOW_1             (EL_DF_FIBRE_OPTIC_START + 2)
+#define EL_DF_FIBRE_OPTIC_YELLOW_2             (EL_DF_FIBRE_OPTIC_START + 3)
+#define EL_DF_FIBRE_OPTIC_GREEN_1              (EL_DF_FIBRE_OPTIC_START + 4)
+#define EL_DF_FIBRE_OPTIC_GREEN_2              (EL_DF_FIBRE_OPTIC_START + 5)
+#define EL_DF_FIBRE_OPTIC_BLUE_1               (EL_DF_FIBRE_OPTIC_START + 6)
+#define EL_DF_FIBRE_OPTIC_BLUE_2               (EL_DF_FIBRE_OPTIC_START + 7)
+#define EL_DF_FIBRE_OPTIC_END                  EL_DF_FIBRE_OPTIC_07
+
+#define EL_DF_MIRROR_ROTATING_START            (EL_DF_START2 + 324)
+#define EL_DF_MIRROR_ROTATING_1                        (EL_DF_MIRROR_ROTATING_START + 0)
+#define EL_DF_MIRROR_ROTATING_2                        (EL_DF_MIRROR_ROTATING_START + 1)
+#define EL_DF_MIRROR_ROTATING_3                        (EL_DF_MIRROR_ROTATING_START + 2)
+#define EL_DF_MIRROR_ROTATING_4                        (EL_DF_MIRROR_ROTATING_START + 3)
+#define EL_DF_MIRROR_ROTATING_5                        (EL_DF_MIRROR_ROTATING_START + 4)
+#define EL_DF_MIRROR_ROTATING_6                        (EL_DF_MIRROR_ROTATING_START + 5)
+#define EL_DF_MIRROR_ROTATING_7                        (EL_DF_MIRROR_ROTATING_START + 6)
+#define EL_DF_MIRROR_ROTATING_8                        (EL_DF_MIRROR_ROTATING_START + 7)
+#define EL_DF_MIRROR_ROTATING_9                        (EL_DF_MIRROR_ROTATING_START + 8)
+#define EL_DF_MIRROR_ROTATING_10               (EL_DF_MIRROR_ROTATING_START + 9)
+#define EL_DF_MIRROR_ROTATING_11               (EL_DF_MIRROR_ROTATING_START + 10)
+#define EL_DF_MIRROR_ROTATING_12               (EL_DF_MIRROR_ROTATING_START + 11)
+#define EL_DF_MIRROR_ROTATING_13               (EL_DF_MIRROR_ROTATING_START + 12)
+#define EL_DF_MIRROR_ROTATING_14               (EL_DF_MIRROR_ROTATING_START + 13)
+#define EL_DF_MIRROR_ROTATING_15               (EL_DF_MIRROR_ROTATING_START + 14)
+#define EL_DF_MIRROR_ROTATING_16               (EL_DF_MIRROR_ROTATING_START + 15)
+#define EL_DF_MIRROR_ROTATING_END              EL_DF_MIRROR_ROTATING_15
+
+#define EL_DF_WOODEN_GRID_ROTATING_START       (EL_DF_START2 + 340)
+#define EL_DF_WOODEN_GRID_ROTATING_1           (EL_DF_WOODEN_GRID_ROTATING_START + 0)
+#define EL_DF_WOODEN_GRID_ROTATING_2           (EL_DF_WOODEN_GRID_ROTATING_START + 1)
+#define EL_DF_WOODEN_GRID_ROTATING_3           (EL_DF_WOODEN_GRID_ROTATING_START + 2)
+#define EL_DF_WOODEN_GRID_ROTATING_4           (EL_DF_WOODEN_GRID_ROTATING_START + 3)
+#define EL_DF_WOODEN_GRID_ROTATING_5           (EL_DF_WOODEN_GRID_ROTATING_START + 4)
+#define EL_DF_WOODEN_GRID_ROTATING_6           (EL_DF_WOODEN_GRID_ROTATING_START + 5)
+#define EL_DF_WOODEN_GRID_ROTATING_7           (EL_DF_WOODEN_GRID_ROTATING_START + 6)
+#define EL_DF_WOODEN_GRID_ROTATING_8           (EL_DF_WOODEN_GRID_ROTATING_START + 7)
+#define EL_DF_WOODEN_GRID_ROTATING_END         EL_DF_WOODEN_GRID_ROTATING_07
+
+#define EL_DF_STEEL_GRID_ROTATING_START                (EL_DF_START2 + 348)
+#define EL_DF_STEEL_GRID_ROTATING_1            (EL_DF_STEEL_GRID_ROTATING_START + 0)
+#define EL_DF_STEEL_GRID_ROTATING_2            (EL_DF_STEEL_GRID_ROTATING_START + 1)
+#define EL_DF_STEEL_GRID_ROTATING_3            (EL_DF_STEEL_GRID_ROTATING_START + 2)
+#define EL_DF_STEEL_GRID_ROTATING_4            (EL_DF_STEEL_GRID_ROTATING_START + 3)
+#define EL_DF_STEEL_GRID_ROTATING_5            (EL_DF_STEEL_GRID_ROTATING_START + 4)
+#define EL_DF_STEEL_GRID_ROTATING_6            (EL_DF_STEEL_GRID_ROTATING_START + 5)
+#define EL_DF_STEEL_GRID_ROTATING_7            (EL_DF_STEEL_GRID_ROTATING_START + 6)
+#define EL_DF_STEEL_GRID_ROTATING_8            (EL_DF_STEEL_GRID_ROTATING_START + 7)
+#define EL_DF_STEEL_GRID_ROTATING_END          EL_DF_STEEL_GRID_ROTATING_07
+
+#define EL_DF_END_1                            (EL_DF_START2 + 355)
+
+// MM style elements
+#define EL_MM_TELEPORTER_RED_START             (EL_DF_START2 + 356)
+#define EL_MM_TELEPORTER_RED_1                 (EL_MM_TELEPORTER_RED_START + 0)
+#define EL_MM_TELEPORTER_RED_2                 (EL_MM_TELEPORTER_RED_START + 1)
+#define EL_MM_TELEPORTER_RED_3                 (EL_MM_TELEPORTER_RED_START + 2)
+#define EL_MM_TELEPORTER_RED_4                 (EL_MM_TELEPORTER_RED_START + 3)
+#define EL_MM_TELEPORTER_RED_5                 (EL_MM_TELEPORTER_RED_START + 4)
+#define EL_MM_TELEPORTER_RED_6                 (EL_MM_TELEPORTER_RED_START + 5)
+#define EL_MM_TELEPORTER_RED_7                 (EL_MM_TELEPORTER_RED_START + 6)
+#define EL_MM_TELEPORTER_RED_8                 (EL_MM_TELEPORTER_RED_START + 7)
+#define EL_MM_TELEPORTER_RED_9                 (EL_MM_TELEPORTER_RED_START + 8)
+#define EL_MM_TELEPORTER_RED_10                        (EL_MM_TELEPORTER_RED_START + 9)
+#define EL_MM_TELEPORTER_RED_11                        (EL_MM_TELEPORTER_RED_START + 10)
+#define EL_MM_TELEPORTER_RED_12                        (EL_MM_TELEPORTER_RED_START + 11)
+#define EL_MM_TELEPORTER_RED_13                        (EL_MM_TELEPORTER_RED_START + 12)
+#define EL_MM_TELEPORTER_RED_14                        (EL_MM_TELEPORTER_RED_START + 13)
+#define EL_MM_TELEPORTER_RED_15                        (EL_MM_TELEPORTER_RED_START + 14)
+#define EL_MM_TELEPORTER_RED_16                        (EL_MM_TELEPORTER_RED_START + 15)
+#define EL_MM_TELEPORTER_RED_END               EL_MM_TELEPORTER_RED_16
+#define EL_MM_TELEPORTER_YELLOW_START          (EL_DF_START2 + 372)
+#define EL_MM_TELEPORTER_YELLOW_1              (EL_MM_TELEPORTER_YELLOW_START + 0)
+#define EL_MM_TELEPORTER_YELLOW_2              (EL_MM_TELEPORTER_YELLOW_START + 1)
+#define EL_MM_TELEPORTER_YELLOW_3              (EL_MM_TELEPORTER_YELLOW_START + 2)
+#define EL_MM_TELEPORTER_YELLOW_4              (EL_MM_TELEPORTER_YELLOW_START + 3)
+#define EL_MM_TELEPORTER_YELLOW_5              (EL_MM_TELEPORTER_YELLOW_START + 4)
+#define EL_MM_TELEPORTER_YELLOW_6              (EL_MM_TELEPORTER_YELLOW_START + 5)
+#define EL_MM_TELEPORTER_YELLOW_7              (EL_MM_TELEPORTER_YELLOW_START + 6)
+#define EL_MM_TELEPORTER_YELLOW_8              (EL_MM_TELEPORTER_YELLOW_START + 7)
+#define EL_MM_TELEPORTER_YELLOW_9              (EL_MM_TELEPORTER_YELLOW_START + 8)
+#define EL_MM_TELEPORTER_YELLOW_10             (EL_MM_TELEPORTER_YELLOW_START + 9)
+#define EL_MM_TELEPORTER_YELLOW_11             (EL_MM_TELEPORTER_YELLOW_START + 10)
+#define EL_MM_TELEPORTER_YELLOW_12             (EL_MM_TELEPORTER_YELLOW_START + 11)
+#define EL_MM_TELEPORTER_YELLOW_13             (EL_MM_TELEPORTER_YELLOW_START + 12)
+#define EL_MM_TELEPORTER_YELLOW_14             (EL_MM_TELEPORTER_YELLOW_START + 13)
+#define EL_MM_TELEPORTER_YELLOW_15             (EL_MM_TELEPORTER_YELLOW_START + 14)
+#define EL_MM_TELEPORTER_YELLOW_16             (EL_MM_TELEPORTER_YELLOW_START + 15)
+#define EL_MM_TELEPORTER_YELLOW_END            EL_MM_TELEPORTER_YELLOW_16
+#define EL_MM_TELEPORTER_GREEN_START           (EL_DF_START2 + 388)
+#define EL_MM_TELEPORTER_GREEN_1               (EL_MM_TELEPORTER_GREEN_START + 0)
+#define EL_MM_TELEPORTER_GREEN_2               (EL_MM_TELEPORTER_GREEN_START + 1)
+#define EL_MM_TELEPORTER_GREEN_3               (EL_MM_TELEPORTER_GREEN_START + 2)
+#define EL_MM_TELEPORTER_GREEN_4               (EL_MM_TELEPORTER_GREEN_START + 3)
+#define EL_MM_TELEPORTER_GREEN_5               (EL_MM_TELEPORTER_GREEN_START + 4)
+#define EL_MM_TELEPORTER_GREEN_6               (EL_MM_TELEPORTER_GREEN_START + 5)
+#define EL_MM_TELEPORTER_GREEN_7               (EL_MM_TELEPORTER_GREEN_START + 6)
+#define EL_MM_TELEPORTER_GREEN_8               (EL_MM_TELEPORTER_GREEN_START + 7)
+#define EL_MM_TELEPORTER_GREEN_9               (EL_MM_TELEPORTER_GREEN_START + 8)
+#define EL_MM_TELEPORTER_GREEN_10              (EL_MM_TELEPORTER_GREEN_START + 9)
+#define EL_MM_TELEPORTER_GREEN_11              (EL_MM_TELEPORTER_GREEN_START + 10)
+#define EL_MM_TELEPORTER_GREEN_12              (EL_MM_TELEPORTER_GREEN_START + 11)
+#define EL_MM_TELEPORTER_GREEN_13              (EL_MM_TELEPORTER_GREEN_START + 12)
+#define EL_MM_TELEPORTER_GREEN_14              (EL_MM_TELEPORTER_GREEN_START + 13)
+#define EL_MM_TELEPORTER_GREEN_15              (EL_MM_TELEPORTER_GREEN_START + 14)
+#define EL_MM_TELEPORTER_GREEN_16              (EL_MM_TELEPORTER_GREEN_START + 15)
+#define EL_MM_TELEPORTER_GREEN_END             EL_MM_TELEPORTER_GREEN_16
+#define EL_MM_TELEPORTER_BLUE_START            (EL_DF_START2 + 404)
+#define EL_MM_TELEPORTER_BLUE_1                        (EL_MM_TELEPORTER_BLUE_START + 0)
+#define EL_MM_TELEPORTER_BLUE_2                        (EL_MM_TELEPORTER_BLUE_START + 1)
+#define EL_MM_TELEPORTER_BLUE_3                        (EL_MM_TELEPORTER_BLUE_START + 2)
+#define EL_MM_TELEPORTER_BLUE_4                        (EL_MM_TELEPORTER_BLUE_START + 3)
+#define EL_MM_TELEPORTER_BLUE_5                        (EL_MM_TELEPORTER_BLUE_START + 4)
+#define EL_MM_TELEPORTER_BLUE_6                        (EL_MM_TELEPORTER_BLUE_START + 5)
+#define EL_MM_TELEPORTER_BLUE_7                        (EL_MM_TELEPORTER_BLUE_START + 6)
+#define EL_MM_TELEPORTER_BLUE_8                        (EL_MM_TELEPORTER_BLUE_START + 7)
+#define EL_MM_TELEPORTER_BLUE_9                        (EL_MM_TELEPORTER_BLUE_START + 8)
+#define EL_MM_TELEPORTER_BLUE_10               (EL_MM_TELEPORTER_BLUE_START + 9)
+#define EL_MM_TELEPORTER_BLUE_11               (EL_MM_TELEPORTER_BLUE_START + 10)
+#define EL_MM_TELEPORTER_BLUE_12               (EL_MM_TELEPORTER_BLUE_START + 11)
+#define EL_MM_TELEPORTER_BLUE_13               (EL_MM_TELEPORTER_BLUE_START + 12)
+#define EL_MM_TELEPORTER_BLUE_14               (EL_MM_TELEPORTER_BLUE_START + 13)
+#define EL_MM_TELEPORTER_BLUE_15               (EL_MM_TELEPORTER_BLUE_START + 14)
+#define EL_MM_TELEPORTER_BLUE_16               (EL_MM_TELEPORTER_BLUE_START + 15)
+#define EL_MM_TELEPORTER_BLUE_END              EL_MM_TELEPORTER_BLUE_16
+
+#define EL_MM_MCDUFFIN                         1204
+#define EL_MM_PACMAN                           1205
+#define EL_MM_FUSE                             1206
+#define EL_MM_STEEL_WALL                       1207
+#define EL_MM_WOODEN_WALL                      1208
+#define EL_MM_ICE_WALL                         1209
+#define EL_MM_AMOEBA_WALL                      1210
+#define EL_DF_LASER                            1211
+#define EL_DF_RECEIVER                         1212
+#define EL_DF_STEEL_WALL                       1213
+#define EL_DF_WOODEN_WALL                      1214
+
+#define EL_MM_END_2                            (EL_DF_START2 + 430)
+
+// EMC style elements
+#define EL_SPRING_LEFT                         1215
+#define EL_SPRING_RIGHT                                1216
+
+// ---------- begin of empty space elements section ---------------------------
+#define EL_EMPTY_SPACE_START                   1217
+
+#include "conf_emp.h"  // include auto-generated data structure definitions
+
+#define NUM_EMPTY_SPACE_ELEMENTS               16
+#define NUM_EMPTY_ELEMENTS_ALL                 (NUM_EMPTY_SPACE_ELEMENTS + 1)
+#define EL_EMPTY_SPACE_END                     1232
+// ---------- end of empty space elements section -----------------------------
+
+#define EL_MM_START_3                          EL_DF_MIRROR_FIXED_START
+#define EL_DF_START_2                          EL_DF_MIRROR_FIXED_START
+
+// DF style elements
+#define EL_DF_MIRROR_FIXED_START               1233
+#define EL_DF_MIRROR_FIXED_1                   (EL_DF_MIRROR_FIXED_START + 0)
+#define EL_DF_MIRROR_FIXED_2                   (EL_DF_MIRROR_FIXED_START + 1)
+#define EL_DF_MIRROR_FIXED_3                   (EL_DF_MIRROR_FIXED_START + 2)
+#define EL_DF_MIRROR_FIXED_4                   (EL_DF_MIRROR_FIXED_START + 3)
+#define EL_DF_MIRROR_FIXED_5                   (EL_DF_MIRROR_FIXED_START + 4)
+#define EL_DF_MIRROR_FIXED_6                   (EL_DF_MIRROR_FIXED_START + 5)
+#define EL_DF_MIRROR_FIXED_7                   (EL_DF_MIRROR_FIXED_START + 6)
+#define EL_DF_MIRROR_FIXED_8                   (EL_DF_MIRROR_FIXED_START + 7)
+#define EL_DF_MIRROR_FIXED_9                   (EL_DF_MIRROR_FIXED_START + 8)
+#define EL_DF_MIRROR_FIXED_10                  (EL_DF_MIRROR_FIXED_START + 9)
+#define EL_DF_MIRROR_FIXED_11                  (EL_DF_MIRROR_FIXED_START + 10)
+#define EL_DF_MIRROR_FIXED_12                  (EL_DF_MIRROR_FIXED_START + 11)
+#define EL_DF_MIRROR_FIXED_13                  (EL_DF_MIRROR_FIXED_START + 12)
+#define EL_DF_MIRROR_FIXED_14                  (EL_DF_MIRROR_FIXED_START + 13)
+#define EL_DF_MIRROR_FIXED_15                  (EL_DF_MIRROR_FIXED_START + 14)
+#define EL_DF_MIRROR_FIXED_16                  (EL_DF_MIRROR_FIXED_START + 15)
+#define EL_DF_MIRROR_FIXED_END                 EL_DF_MIRROR_FIXED_16
+
+#define EL_DF_SLOPE_START                      1249
+#define EL_DF_SLOPE_1                          (EL_DF_SLOPE_START + 0)
+#define EL_DF_SLOPE_2                          (EL_DF_SLOPE_START + 1)
+#define EL_DF_SLOPE_3                          (EL_DF_SLOPE_START + 2)
+#define EL_DF_SLOPE_4                          (EL_DF_SLOPE_START + 3)
+#define EL_DF_SLOPE_END                                EL_DF_SLOPE_4
+
+#define EL_MM_END_3                            EL_DF_SLOPE_END
+#define EL_DF_END_2                            EL_DF_SLOPE_END
+
+// BD style elements (normal)
+#define EL_BDX_START                           1253
+#define EL_BDX_EMPTY_SPACE                     EL_BDX_START
+#define EL_BDX_EMPTY                           EL_BDX_EMPTY_SPACE
+#define EL_BDX_SAND_1                          1254
+#define EL_BDX_SAND_2                          1255
+#define EL_BDX_SAND_BALL                       1256
+#define EL_BDX_SAND_LOOSE                      1257
+#define EL_BDX_SAND_SLOPED_UP_RIGHT            1258
+#define EL_BDX_SAND_SLOPED_UP_LEFT             1259
+#define EL_BDX_SAND_SLOPED_DOWN_LEFT           1260
+#define EL_BDX_SAND_SLOPED_DOWN_RIGHT          1261
+#define EL_BDX_SAND_GLUED                      1262
+#define EL_BDX_WALL_SLOPED_UP_RIGHT            1263
+#define EL_BDX_WALL_SLOPED_UP_LEFT             1264
+#define EL_BDX_WALL_SLOPED_DOWN_LEFT           1265
+#define EL_BDX_WALL_SLOPED_DOWN_RIGHT          1266
+#define EL_BDX_WALL_NON_SLOPED                 1267
+#define EL_BDX_WALL_DIGGABLE                   1268
+#define EL_BDX_WALL_DIAMOND                    1269
+#define EL_BDX_WALL_KEY_1                      1270
+#define EL_BDX_WALL_KEY_2                      1271
+#define EL_BDX_WALL_KEY_3                      1272
+#define EL_BDX_FALLING_WALL                    1273
+#define EL_BDX_STEELWALL                       1274
+#define EL_BDX_STEELWALL_SLOPED_UP_RIGHT       1275
+#define EL_BDX_STEELWALL_SLOPED_UP_LEFT                1276
+#define EL_BDX_STEELWALL_SLOPED_DOWN_LEFT      1277
+#define EL_BDX_STEELWALL_SLOPED_DOWN_RIGHT     1278
+#define EL_BDX_STEELWALL_EXPLODABLE            1279
+#define EL_BDX_STEELWALL_DIGGABLE              1280
+#define EL_BDX_EXPANDABLE_WALL_HORIZONTAL      1281
+#define EL_BDX_EXPANDABLE_WALL_VERTICAL                1282
+#define EL_BDX_EXPANDABLE_WALL_ANY             1283
+#define EL_BDX_EXPANDABLE_STEELWALL_HORIZONTAL 1284
+#define EL_BDX_EXPANDABLE_STEELWALL_VERTICAL   1285
+#define EL_BDX_EXPANDABLE_STEELWALL_ANY                1286
+#define EL_BDX_EXPANDABLE_WALL_SWITCH          1287
+#define EL_BDX_EXPANDABLE_WALL_SWITCH_ACTIVE   1288
+#define EL_BDX_INBOX                           1289
+#define EL_BDX_EXIT_CLOSED                     1290
+#define EL_BDX_EXIT_OPEN                       1291
+#define EL_BDX_INVISIBLE_EXIT_CLOSED           1292
+#define EL_BDX_INVISIBLE_EXIT_OPEN             1293
+#define EL_BDX_FLYING_ROCK                     1294
+#define EL_BDX_MEGA_ROCK                       1295
+#define EL_BDX_ROCK_GLUED                      1296
+#define EL_BDX_FLYING_DIAMOND                  1297
+#define EL_BDX_DIAMOND_GLUED                   1298
+#define EL_BDX_DIAMOND_KEY                     1299
+#define EL_BDX_TRAPPED_DIAMOND                 1300
+#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_CREATURE_SWITCH                 1306
+#define EL_BDX_CREATURE_SWITCH_ACTIVE          1307
+#define EL_BDX_BITER_SWITCH_1                  1308
+#define EL_BDX_BITER_SWITCH_2                  1309
+#define EL_BDX_BITER_SWITCH_3                  1310
+#define EL_BDX_BITER_SWITCH_4                  1311
+#define EL_BDX_REPLICATOR                      1312
+#define EL_BDX_REPLICATOR_ACTIVE               1313
+#define EL_BDX_REPLICATOR_SWITCH               1314
+#define EL_BDX_REPLICATOR_SWITCH_ACTIVE                1315
+#define EL_BDX_CONVEYOR_LEFT                   1316
+#define EL_BDX_CONVEYOR_LEFT_ACTIVE            1317
+#define EL_BDX_CONVEYOR_RIGHT                  1318
+#define EL_BDX_CONVEYOR_RIGHT_ACTIVE           1319
+#define EL_BDX_CONVEYOR_SWITCH                 1320
+#define EL_BDX_CONVEYOR_SWITCH_ACTIVE          1321
+#define EL_BDX_CONVEYOR_DIR_SWITCH             1322
+#define EL_BDX_CONVEYOR_DIR_SWITCH_ACTIVE      1323
+#define EL_BDX_GRAVITY_SWITCH                  1324
+#define EL_BDX_GRAVITY_SWITCH_ACTIVE           1325
+#define EL_BDX_ACID                            1326
+#define EL_BDX_BOX                             1327
+#define EL_BDX_TIME_PENALTY                    1328
+#define EL_BDX_GRAVESTONE                      1329
+#define EL_BDX_CLOCK                           1330
+#define EL_BDX_POT                             1331
+#define EL_BDX_PNEUMATIC_HAMMER                        1332
+#define EL_BDX_TELEPORTER                      1333
+#define EL_BDX_SKELETON                                1334
+#define EL_BDX_WATER                           1335
+#define EL_BDX_KEY_1                           1336
+#define EL_BDX_KEY_2                           1337
+#define EL_BDX_KEY_3                           1338
+#define EL_BDX_GATE_1                          1339
+#define EL_BDX_GATE_2                          1340
+#define EL_BDX_GATE_3                          1341
+#define EL_BDX_LAVA                            1342
+#define EL_BDX_SWEET                           1343
+#define EL_BDX_VOODOO_DOLL                     1344
+#define EL_BDX_SLIME                           1345
+#define EL_BDX_WAITING_ROCK                    1346
+#define EL_BDX_CHASING_ROCK                    1347
+#define EL_BDX_GHOST                           1348
+#define EL_BDX_COW                             1349
+#define EL_BDX_COW_LEFT                                1350
+#define EL_BDX_COW_UP                          1351
+#define EL_BDX_COW_RIGHT                       1352
+#define EL_BDX_COW_DOWN                                1353
+#define EL_BDX_BUTTERFLY_1                     1354
+#define EL_BDX_BUTTERFLY_1_RIGHT               1355
+#define EL_BDX_BUTTERFLY_1_UP                  1356
+#define EL_BDX_BUTTERFLY_1_LEFT                        1357
+#define EL_BDX_BUTTERFLY_1_DOWN                        1358
+#define EL_BDX_BUTTERFLY_2                     1359
+#define EL_BDX_BUTTERFLY_2_RIGHT               1360
+#define EL_BDX_BUTTERFLY_2_UP                  1361
+#define EL_BDX_BUTTERFLY_2_LEFT                        1362
+#define EL_BDX_BUTTERFLY_2_DOWN                        1363
+#define EL_BDX_FIREFLY_1                       1364
+#define EL_BDX_FIREFLY_1_RIGHT                 1365
+#define EL_BDX_FIREFLY_1_UP                    1366
+#define EL_BDX_FIREFLY_1_LEFT                  1367
+#define EL_BDX_FIREFLY_1_DOWN                  1368
+#define EL_BDX_FIREFLY_2                       1369
+#define EL_BDX_FIREFLY_2_RIGHT                 1370
+#define EL_BDX_FIREFLY_2_UP                    1371
+#define EL_BDX_FIREFLY_2_LEFT                  1372
+#define EL_BDX_FIREFLY_2_DOWN                  1373
+#define EL_BDX_STONEFLY                                1374
+#define EL_BDX_STONEFLY_RIGHT                  1375
+#define EL_BDX_STONEFLY_UP                     1376
+#define EL_BDX_STONEFLY_LEFT                   1377
+#define EL_BDX_STONEFLY_DOWN                   1378
+#define EL_BDX_BITER                           1379
+#define EL_BDX_BITER_RIGHT                     1380
+#define EL_BDX_BITER_UP                                1381
+#define EL_BDX_BITER_LEFT                      1382
+#define EL_BDX_BITER_DOWN                      1383
+#define EL_BDX_DRAGONFLY                       1384
+#define EL_BDX_DRAGONFLY_RIGHT                 1385
+#define EL_BDX_DRAGONFLY_UP                    1386
+#define EL_BDX_DRAGONFLY_LEFT                  1387
+#define EL_BDX_DRAGONFLY_DOWN                  1388
+#define EL_BDX_BOMB                            1389
+#define EL_BDX_NITRO_PACK                      1390
+#define EL_BDX_PLAYER                          1391
+#define EL_BDX_PLAYER_WITH_BOMB                        1392
+#define EL_BDX_PLAYER_WITH_ROCKET_LAUNCHER     1393
+#define EL_BDX_PLAYER_GLUED                    1394
+#define EL_BDX_PLAYER_STIRRING                 1395
+#define EL_BDX_ROCKET_LAUNCHER                 1396
+#define EL_BDX_ROCKET                          1397
+#define EL_BDX_ROCKET_RIGHT                    1398
+#define EL_BDX_ROCKET_UP                       1399
+#define EL_BDX_ROCKET_LEFT                     1400
+#define EL_BDX_ROCKET_DOWN                     1401
+#define EL_BDX_FAKE_BONUS                      1402
+#define EL_BDX_COVERED                         1403
+#define EL_BDX_WALL                            1404
+#define EL_BDX_ROCK                            1405
+#define EL_BDX_DIAMOND                         1406
+#define EL_BDX_MAGIC_WALL                      1407
+
+// BD style elements ("effects"; mostly runtime elements, but can also be stored in level file)
+#define EL_BDX_RUNTIME_START                   1408
+#define EL_BDX_SAND_BALL_FALLING               EL_BDX_RUNTIME_START
+#define EL_BDX_SAND_LOOSE_FALLING              1409
+#define EL_BDX_ROCK_FALLING                    1410
+#define EL_BDX_FLYING_ROCK_FLYING              1411
+#define EL_BDX_MEGA_ROCK_FALLING               1412
+#define EL_BDX_DIAMOND_FALLING                 1413
+#define EL_BDX_FLYING_DIAMOND_FLYING           1414
+#define EL_BDX_NUT_FALLING                     1415
+#define EL_BDX_FALLING_WALL_FALLING            1416
+#define EL_BDX_NITRO_PACK_FALLING              1417
+#define EL_BDX_WATER_1                         1418
+#define EL_BDX_WATER_2                         1419
+#define EL_BDX_WATER_3                         1420
+#define EL_BDX_WATER_4                         1421
+#define EL_BDX_WATER_5                         1422
+#define EL_BDX_WATER_6                         1423
+#define EL_BDX_WATER_7                         1424
+#define EL_BDX_WATER_8                         1425
+#define EL_BDX_WATER_9                         1426
+#define EL_BDX_WATER_10                                1427
+#define EL_BDX_WATER_11                                1428
+#define EL_BDX_WATER_12                                1429
+#define EL_BDX_WATER_13                                1430
+#define EL_BDX_WATER_14                                1431
+#define EL_BDX_WATER_15                                1432
+#define EL_BDX_WATER_16                                1433
+#define EL_BDX_COW_ENCLOSED_1                  1434
+#define EL_BDX_COW_ENCLOSED_2                  1435
+#define EL_BDX_COW_ENCLOSED_3                  1436
+#define EL_BDX_COW_ENCLOSED_4                  1437
+#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_PLAYER_GROWING_1                        1449
+#define EL_BDX_PLAYER_GROWING_2                        1450
+#define EL_BDX_PLAYER_GROWING_3                        1451
+#define EL_BDX_BOMB_TICKING_1                  1452
+#define EL_BDX_BOMB_TICKING_2                  1453
+#define EL_BDX_BOMB_TICKING_3                  1454
+#define EL_BDX_BOMB_TICKING_4                  1455
+#define EL_BDX_BOMB_TICKING_5                  1456
+#define EL_BDX_BOMB_TICKING_6                  1457
+#define EL_BDX_BOMB_TICKING_7                  1458
+#define EL_BDX_CLOCK_GROWING_1                 1459
+#define EL_BDX_CLOCK_GROWING_2                 1460
+#define EL_BDX_CLOCK_GROWING_3                 1461
+#define EL_BDX_CLOCK_GROWING_4                 1462
+#define EL_BDX_DIAMOND_GROWING_1               1463
+#define EL_BDX_DIAMOND_GROWING_2               1464
+#define EL_BDX_DIAMOND_GROWING_3               1465
+#define EL_BDX_DIAMOND_GROWING_4               1466
+#define EL_BDX_DIAMOND_GROWING_5               1467
+#define EL_BDX_EXPLODING_1                     1468
+#define EL_BDX_EXPLODING_2                     1469
+#define EL_BDX_EXPLODING_3                     1470
+#define EL_BDX_EXPLODING_4                     1471
+#define EL_BDX_EXPLODING_5                     1472
+#define EL_BDX_ROCK_GROWING_1                  1473
+#define EL_BDX_ROCK_GROWING_2                  1474
+#define EL_BDX_ROCK_GROWING_3                  1475
+#define EL_BDX_ROCK_GROWING_4                  1476
+#define EL_BDX_STEELWALL_GROWING_1             1477
+#define EL_BDX_STEELWALL_GROWING_2             1478
+#define EL_BDX_STEELWALL_GROWING_3             1479
+#define EL_BDX_STEELWALL_GROWING_4             1480
+#define EL_BDX_GHOST_EXPLODING_1               1481
+#define EL_BDX_GHOST_EXPLODING_2               1482
+#define EL_BDX_GHOST_EXPLODING_3               1483
+#define EL_BDX_GHOST_EXPLODING_4               1484
+#define EL_BDX_BOMB_EXPLODING_1                        1485
+#define EL_BDX_BOMB_EXPLODING_2                        1486
+#define EL_BDX_BOMB_EXPLODING_3                        1487
+#define EL_BDX_BOMB_EXPLODING_4                        1488
+#define EL_BDX_NITRO_PACK_EXPLODING            1489
+#define EL_BDX_NITRO_PACK_EXPLODING_1          1490
+#define EL_BDX_NITRO_PACK_EXPLODING_2          1491
+#define EL_BDX_NITRO_PACK_EXPLODING_3          1492
+#define EL_BDX_NITRO_PACK_EXPLODING_4          1493
+#define EL_BDX_AMOEBA_2_EXPLODING_1            1494
+#define EL_BDX_AMOEBA_2_EXPLODING_2            1495
+#define EL_BDX_AMOEBA_2_EXPLODING_3            1496
+#define EL_BDX_AMOEBA_2_EXPLODING_4            1497
+#define EL_BDX_NUT_BREAKING_1                  1498
+#define EL_BDX_NUT_BREAKING_2                  1499
+#define EL_BDX_NUT_BREAKING_3                  1500
+#define EL_BDX_NUT_BREAKING_4                  1501
+#define EL_BDX_RUNTIME_END                     EL_BDX_NUT_BREAKING_4
+#define EL_BDX_END                             EL_BDX_RUNTIME_END
+
+#define NUM_FILE_ELEMENTS                      1502
 
 
 // "real" (and therefore drawable) runtime elements
-#define EL_FIRST_RUNTIME_REAL          NUM_FILE_ELEMENTS
-
-#define EL_DYNABOMB_PLAYER_1_ACTIVE    (EL_FIRST_RUNTIME_REAL + 0)
-#define EL_DYNABOMB_PLAYER_2_ACTIVE    (EL_FIRST_RUNTIME_REAL + 1)
-#define EL_DYNABOMB_PLAYER_3_ACTIVE    (EL_FIRST_RUNTIME_REAL + 2)
-#define EL_DYNABOMB_PLAYER_4_ACTIVE    (EL_FIRST_RUNTIME_REAL + 3)
-#define EL_SP_DISK_RED_ACTIVE          (EL_FIRST_RUNTIME_REAL + 4)
-#define EL_SWITCHGATE_OPENING          (EL_FIRST_RUNTIME_REAL + 5)
-#define EL_SWITCHGATE_CLOSING          (EL_FIRST_RUNTIME_REAL + 6)
-#define EL_TIMEGATE_OPENING            (EL_FIRST_RUNTIME_REAL + 7)
-#define EL_TIMEGATE_CLOSING            (EL_FIRST_RUNTIME_REAL + 8)
-#define EL_PEARL_BREAKING              (EL_FIRST_RUNTIME_REAL + 9)
-#define EL_TRAP_ACTIVE                 (EL_FIRST_RUNTIME_REAL + 10)
-#define EL_INVISIBLE_STEELWALL_ACTIVE  (EL_FIRST_RUNTIME_REAL + 11)
-#define EL_INVISIBLE_WALL_ACTIVE       (EL_FIRST_RUNTIME_REAL + 12)
-#define EL_INVISIBLE_SAND_ACTIVE       (EL_FIRST_RUNTIME_REAL + 13)
-#define EL_CONVEYOR_BELT_1_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 14)
-#define EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 15)
-#define EL_CONVEYOR_BELT_1_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 16)
-#define EL_CONVEYOR_BELT_2_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 17)
-#define EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 18)
-#define EL_CONVEYOR_BELT_2_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 19)
-#define EL_CONVEYOR_BELT_3_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 20)
-#define EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 21)
-#define EL_CONVEYOR_BELT_3_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 22)
-#define EL_CONVEYOR_BELT_4_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 23)
-#define EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 24)
-#define EL_CONVEYOR_BELT_4_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 25)
-#define EL_EXIT_OPENING                        (EL_FIRST_RUNTIME_REAL + 26)
-#define EL_EXIT_CLOSING                        (EL_FIRST_RUNTIME_REAL + 27)
-#define EL_STEEL_EXIT_OPENING          (EL_FIRST_RUNTIME_REAL + 28)
-#define EL_STEEL_EXIT_CLOSING          (EL_FIRST_RUNTIME_REAL + 29)
-#define EL_EM_EXIT_OPENING             (EL_FIRST_RUNTIME_REAL + 30)
-#define EL_EM_EXIT_CLOSING             (EL_FIRST_RUNTIME_REAL + 31)
-#define EL_EM_STEEL_EXIT_OPENING       (EL_FIRST_RUNTIME_REAL + 32)
-#define EL_EM_STEEL_EXIT_CLOSING       (EL_FIRST_RUNTIME_REAL + 33)
-#define EL_SP_EXIT_OPENING             (EL_FIRST_RUNTIME_REAL + 34)
-#define EL_SP_EXIT_CLOSING             (EL_FIRST_RUNTIME_REAL + 35)
-#define EL_SP_EXIT_OPEN                        (EL_FIRST_RUNTIME_REAL + 36)
-#define EL_SP_TERMINAL_ACTIVE          (EL_FIRST_RUNTIME_REAL + 37)
-#define EL_SP_BUGGY_BASE_ACTIVATING    (EL_FIRST_RUNTIME_REAL + 38)
-#define EL_SP_BUGGY_BASE_ACTIVE                (EL_FIRST_RUNTIME_REAL + 39)
-#define EL_SP_MURPHY_CLONE             (EL_FIRST_RUNTIME_REAL + 40)
-#define EL_AMOEBA_DROPPING             (EL_FIRST_RUNTIME_REAL + 41)
-#define EL_QUICKSAND_EMPTYING          (EL_FIRST_RUNTIME_REAL + 42)
-#define EL_QUICKSAND_FAST_EMPTYING     (EL_FIRST_RUNTIME_REAL + 43)
-#define EL_MAGIC_WALL_ACTIVE           (EL_FIRST_RUNTIME_REAL + 44)
-#define EL_BD_MAGIC_WALL_ACTIVE                (EL_FIRST_RUNTIME_REAL + 45)
-#define EL_DC_MAGIC_WALL_ACTIVE                (EL_FIRST_RUNTIME_REAL + 46)
-#define EL_MAGIC_WALL_FULL             (EL_FIRST_RUNTIME_REAL + 47)
-#define EL_BD_MAGIC_WALL_FULL          (EL_FIRST_RUNTIME_REAL + 48)
-#define EL_DC_MAGIC_WALL_FULL          (EL_FIRST_RUNTIME_REAL + 49)
-#define EL_MAGIC_WALL_EMPTYING         (EL_FIRST_RUNTIME_REAL + 50)
-#define EL_BD_MAGIC_WALL_EMPTYING      (EL_FIRST_RUNTIME_REAL + 51)
-#define EL_DC_MAGIC_WALL_EMPTYING      (EL_FIRST_RUNTIME_REAL + 52)
-#define EL_MAGIC_WALL_DEAD             (EL_FIRST_RUNTIME_REAL + 53)
-#define EL_BD_MAGIC_WALL_DEAD          (EL_FIRST_RUNTIME_REAL + 54)
-#define EL_DC_MAGIC_WALL_DEAD          (EL_FIRST_RUNTIME_REAL + 55)
-#define EL_EMC_FAKE_GRASS_ACTIVE       (EL_FIRST_RUNTIME_REAL + 56)
-#define EL_GATE_1_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 57)
-#define EL_GATE_2_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 58)
-#define EL_GATE_3_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 59)
-#define EL_GATE_4_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 60)
-#define EL_EM_GATE_1_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 61)
-#define EL_EM_GATE_2_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 62)
-#define EL_EM_GATE_3_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 63)
-#define EL_EM_GATE_4_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 64)
-#define EL_EMC_GATE_5_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 65)
-#define EL_EMC_GATE_6_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 66)
-#define EL_EMC_GATE_7_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 67)
-#define EL_EMC_GATE_8_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 68)
-#define EL_DC_GATE_WHITE_GRAY_ACTIVE   (EL_FIRST_RUNTIME_REAL + 69)
-#define EL_EMC_DRIPPER_ACTIVE          (EL_FIRST_RUNTIME_REAL + 70)
-#define EL_EMC_SPRING_BUMPER_ACTIVE    (EL_FIRST_RUNTIME_REAL + 71)
-#define EL_MM_EXIT_OPENING             (EL_FIRST_RUNTIME_REAL + 72)
-#define EL_MM_EXIT_CLOSING             (EL_FIRST_RUNTIME_REAL + 73)
-#define EL_MM_GRAY_BALL_OPENING                (EL_FIRST_RUNTIME_REAL + 74)
-#define EL_MM_ICE_WALL_SHRINKING       (EL_FIRST_RUNTIME_REAL + 75)
-#define EL_MM_AMOEBA_WALL_GROWING      (EL_FIRST_RUNTIME_REAL + 76)
-#define EL_MM_PACMAN_EATING_RIGHT      (EL_FIRST_RUNTIME_REAL + 77)
-#define EL_MM_PACMAN_EATING_UP         (EL_FIRST_RUNTIME_REAL + 78)
-#define EL_MM_PACMAN_EATING_LEFT       (EL_FIRST_RUNTIME_REAL + 79)
-#define EL_MM_PACMAN_EATING_DOWN       (EL_FIRST_RUNTIME_REAL + 80)
-
-#define NUM_DRAWABLE_ELEMENTS          (EL_FIRST_RUNTIME_REAL + 81)
-
-#define EL_MM_RUNTIME_START            EL_MM_EXIT_OPENING
-#define EL_MM_RUNTIME_END              EL_MM_AMOEBA_WALL_GROWING
+#define EL_FIRST_RUNTIME_REAL                  NUM_FILE_ELEMENTS
+
+#define EL_DYNABOMB_PLAYER_1_ACTIVE            (EL_FIRST_RUNTIME_REAL + 0)
+#define EL_DYNABOMB_PLAYER_2_ACTIVE            (EL_FIRST_RUNTIME_REAL + 1)
+#define EL_DYNABOMB_PLAYER_3_ACTIVE            (EL_FIRST_RUNTIME_REAL + 2)
+#define EL_DYNABOMB_PLAYER_4_ACTIVE            (EL_FIRST_RUNTIME_REAL + 3)
+#define EL_SP_DISK_RED_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 4)
+#define EL_SWITCHGATE_OPENING                  (EL_FIRST_RUNTIME_REAL + 5)
+#define EL_SWITCHGATE_CLOSING                  (EL_FIRST_RUNTIME_REAL + 6)
+#define EL_TIMEGATE_OPENING                    (EL_FIRST_RUNTIME_REAL + 7)
+#define EL_TIMEGATE_CLOSING                    (EL_FIRST_RUNTIME_REAL + 8)
+#define EL_PEARL_BREAKING                      (EL_FIRST_RUNTIME_REAL + 9)
+#define EL_TRAP_ACTIVE                         (EL_FIRST_RUNTIME_REAL + 10)
+#define EL_INVISIBLE_STEELWALL_ACTIVE          (EL_FIRST_RUNTIME_REAL + 11)
+#define EL_INVISIBLE_WALL_ACTIVE               (EL_FIRST_RUNTIME_REAL + 12)
+#define EL_INVISIBLE_SAND_ACTIVE               (EL_FIRST_RUNTIME_REAL + 13)
+#define EL_CONVEYOR_BELT_1_LEFT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 14)
+#define EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE       (EL_FIRST_RUNTIME_REAL + 15)
+#define EL_CONVEYOR_BELT_1_RIGHT_ACTIVE                (EL_FIRST_RUNTIME_REAL + 16)
+#define EL_CONVEYOR_BELT_2_LEFT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 17)
+#define EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE       (EL_FIRST_RUNTIME_REAL + 18)
+#define EL_CONVEYOR_BELT_2_RIGHT_ACTIVE                (EL_FIRST_RUNTIME_REAL + 19)
+#define EL_CONVEYOR_BELT_3_LEFT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 20)
+#define EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE       (EL_FIRST_RUNTIME_REAL + 21)
+#define EL_CONVEYOR_BELT_3_RIGHT_ACTIVE                (EL_FIRST_RUNTIME_REAL + 22)
+#define EL_CONVEYOR_BELT_4_LEFT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 23)
+#define EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE       (EL_FIRST_RUNTIME_REAL + 24)
+#define EL_CONVEYOR_BELT_4_RIGHT_ACTIVE                (EL_FIRST_RUNTIME_REAL + 25)
+#define EL_EXIT_OPENING                                (EL_FIRST_RUNTIME_REAL + 26)
+#define EL_EXIT_CLOSING                                (EL_FIRST_RUNTIME_REAL + 27)
+#define EL_STEEL_EXIT_OPENING                  (EL_FIRST_RUNTIME_REAL + 28)
+#define EL_STEEL_EXIT_CLOSING                  (EL_FIRST_RUNTIME_REAL + 29)
+#define EL_EM_EXIT_OPENING                     (EL_FIRST_RUNTIME_REAL + 30)
+#define EL_EM_EXIT_CLOSING                     (EL_FIRST_RUNTIME_REAL + 31)
+#define EL_EM_STEEL_EXIT_OPENING               (EL_FIRST_RUNTIME_REAL + 32)
+#define EL_EM_STEEL_EXIT_CLOSING               (EL_FIRST_RUNTIME_REAL + 33)
+#define EL_SP_EXIT_OPENING                     (EL_FIRST_RUNTIME_REAL + 34)
+#define EL_SP_EXIT_CLOSING                     (EL_FIRST_RUNTIME_REAL + 35)
+#define EL_SP_EXIT_OPEN                                (EL_FIRST_RUNTIME_REAL + 36)
+#define EL_SP_TERMINAL_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 37)
+#define EL_SP_BUGGY_BASE_ACTIVATING            (EL_FIRST_RUNTIME_REAL + 38)
+#define EL_SP_BUGGY_BASE_ACTIVE                        (EL_FIRST_RUNTIME_REAL + 39)
+#define EL_SP_MURPHY_CLONE                     (EL_FIRST_RUNTIME_REAL + 40)
+#define EL_AMOEBA_DROPPING                     (EL_FIRST_RUNTIME_REAL + 41)
+#define EL_QUICKSAND_EMPTYING                  (EL_FIRST_RUNTIME_REAL + 42)
+#define EL_QUICKSAND_FAST_EMPTYING             (EL_FIRST_RUNTIME_REAL + 43)
+#define EL_MAGIC_WALL_ACTIVE                   (EL_FIRST_RUNTIME_REAL + 44)
+#define EL_BD_MAGIC_WALL_ACTIVE                        (EL_FIRST_RUNTIME_REAL + 45)
+#define EL_DC_MAGIC_WALL_ACTIVE                        (EL_FIRST_RUNTIME_REAL + 46)
+#define EL_MAGIC_WALL_FULL                     (EL_FIRST_RUNTIME_REAL + 47)
+#define EL_BD_MAGIC_WALL_FULL                  (EL_FIRST_RUNTIME_REAL + 48)
+#define EL_DC_MAGIC_WALL_FULL                  (EL_FIRST_RUNTIME_REAL + 49)
+#define EL_MAGIC_WALL_EMPTYING                 (EL_FIRST_RUNTIME_REAL + 50)
+#define EL_BD_MAGIC_WALL_EMPTYING              (EL_FIRST_RUNTIME_REAL + 51)
+#define EL_DC_MAGIC_WALL_EMPTYING              (EL_FIRST_RUNTIME_REAL + 52)
+#define EL_MAGIC_WALL_DEAD                     (EL_FIRST_RUNTIME_REAL + 53)
+#define EL_BD_MAGIC_WALL_DEAD                  (EL_FIRST_RUNTIME_REAL + 54)
+#define EL_DC_MAGIC_WALL_DEAD                  (EL_FIRST_RUNTIME_REAL + 55)
+#define EL_EMC_FAKE_GRASS_ACTIVE               (EL_FIRST_RUNTIME_REAL + 56)
+#define EL_GATE_1_GRAY_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 57)
+#define EL_GATE_2_GRAY_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 58)
+#define EL_GATE_3_GRAY_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 59)
+#define EL_GATE_4_GRAY_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 60)
+#define EL_EM_GATE_1_GRAY_ACTIVE               (EL_FIRST_RUNTIME_REAL + 61)
+#define EL_EM_GATE_2_GRAY_ACTIVE               (EL_FIRST_RUNTIME_REAL + 62)
+#define EL_EM_GATE_3_GRAY_ACTIVE               (EL_FIRST_RUNTIME_REAL + 63)
+#define EL_EM_GATE_4_GRAY_ACTIVE               (EL_FIRST_RUNTIME_REAL + 64)
+#define EL_EMC_GATE_5_GRAY_ACTIVE              (EL_FIRST_RUNTIME_REAL + 65)
+#define EL_EMC_GATE_6_GRAY_ACTIVE              (EL_FIRST_RUNTIME_REAL + 66)
+#define EL_EMC_GATE_7_GRAY_ACTIVE              (EL_FIRST_RUNTIME_REAL + 67)
+#define EL_EMC_GATE_8_GRAY_ACTIVE              (EL_FIRST_RUNTIME_REAL + 68)
+#define EL_DC_GATE_WHITE_GRAY_ACTIVE           (EL_FIRST_RUNTIME_REAL + 69)
+#define EL_EMC_DRIPPER_ACTIVE                  (EL_FIRST_RUNTIME_REAL + 70)
+#define EL_EMC_SPRING_BUMPER_ACTIVE            (EL_FIRST_RUNTIME_REAL + 71)
+#define EL_MM_EXIT_OPENING                     (EL_FIRST_RUNTIME_REAL + 72)
+#define EL_MM_EXIT_CLOSING                     (EL_FIRST_RUNTIME_REAL + 73)
+#define EL_MM_GRAY_BALL_ACTIVE                 (EL_FIRST_RUNTIME_REAL + 74)
+#define EL_MM_GRAY_BALL_OPENING                        (EL_FIRST_RUNTIME_REAL + 75)
+#define EL_MM_ICE_WALL_SHRINKING               (EL_FIRST_RUNTIME_REAL + 76)
+#define EL_MM_AMOEBA_WALL_GROWING              (EL_FIRST_RUNTIME_REAL + 77)
+#define EL_MM_PACMAN_EATING_RIGHT              (EL_FIRST_RUNTIME_REAL + 78)
+#define EL_MM_PACMAN_EATING_UP                 (EL_FIRST_RUNTIME_REAL + 79)
+#define EL_MM_PACMAN_EATING_LEFT               (EL_FIRST_RUNTIME_REAL + 80)
+#define EL_MM_PACMAN_EATING_DOWN               (EL_FIRST_RUNTIME_REAL + 81)
+#define EL_MM_BOMB_ACTIVE                      (EL_FIRST_RUNTIME_REAL + 82)
+#define EL_DF_MINE_ACTIVE                      (EL_FIRST_RUNTIME_REAL + 83)
+#define EL_BDX_MAGIC_WALL_ACTIVE               (EL_FIRST_RUNTIME_REAL + 84)
+
+#define NUM_DRAWABLE_ELEMENTS                  (EL_FIRST_RUNTIME_REAL + 85)
+
+#define EL_MM_RUNTIME_START                    EL_MM_EXIT_OPENING
+#define EL_MM_RUNTIME_END                      EL_MM_AMOEBA_WALL_GROWING
 
 // "unreal" (and therefore not drawable) runtime elements
-#define EL_FIRST_RUNTIME_UNREAL                (NUM_DRAWABLE_ELEMENTS)
-
-#define EL_BLOCKED                     (EL_FIRST_RUNTIME_UNREAL + 0)
-#define EL_EXPLOSION                   (EL_FIRST_RUNTIME_UNREAL + 1)
-#define EL_NUT_BREAKING                        (EL_FIRST_RUNTIME_UNREAL + 2)
-#define EL_DIAMOND_BREAKING            (EL_FIRST_RUNTIME_UNREAL + 3)
-#define EL_ACID_SPLASH_LEFT            (EL_FIRST_RUNTIME_UNREAL + 4)
-#define EL_ACID_SPLASH_RIGHT           (EL_FIRST_RUNTIME_UNREAL + 5)
-#define EL_AMOEBA_GROWING              (EL_FIRST_RUNTIME_UNREAL + 6)
-#define EL_AMOEBA_SHRINKING            (EL_FIRST_RUNTIME_UNREAL + 7)
-#define EL_EXPANDABLE_WALL_GROWING     (EL_FIRST_RUNTIME_UNREAL + 8)
-#define EL_EXPANDABLE_STEELWALL_GROWING        (EL_FIRST_RUNTIME_UNREAL + 9)
-#define EL_FLAMES                      (EL_FIRST_RUNTIME_UNREAL + 10)
-#define EL_PLAYER_IS_LEAVING           (EL_FIRST_RUNTIME_UNREAL + 11)
-#define EL_PLAYER_IS_EXPLODING_1       (EL_FIRST_RUNTIME_UNREAL + 12)
-#define EL_PLAYER_IS_EXPLODING_2       (EL_FIRST_RUNTIME_UNREAL + 13)
-#define EL_PLAYER_IS_EXPLODING_3       (EL_FIRST_RUNTIME_UNREAL + 14)
-#define EL_PLAYER_IS_EXPLODING_4       (EL_FIRST_RUNTIME_UNREAL + 15)
-#define EL_QUICKSAND_FILLING           (EL_FIRST_RUNTIME_UNREAL + 16)
-#define EL_QUICKSAND_FAST_FILLING      (EL_FIRST_RUNTIME_UNREAL + 17)
-#define EL_MAGIC_WALL_FILLING          (EL_FIRST_RUNTIME_UNREAL + 18)
-#define EL_BD_MAGIC_WALL_FILLING       (EL_FIRST_RUNTIME_UNREAL + 19)
-#define EL_DC_MAGIC_WALL_FILLING       (EL_FIRST_RUNTIME_UNREAL + 20)
-#define EL_ELEMENT_SNAPPING            (EL_FIRST_RUNTIME_UNREAL + 21)
-#define EL_DIAGONAL_SHRINKING          (EL_FIRST_RUNTIME_UNREAL + 22)
-#define EL_DIAGONAL_GROWING            (EL_FIRST_RUNTIME_UNREAL + 23)
-
-#define NUM_RUNTIME_ELEMENTS           (EL_FIRST_RUNTIME_UNREAL + 24)
+#define EL_FIRST_RUNTIME_UNREAL                        (NUM_DRAWABLE_ELEMENTS)
+
+#define EL_BLOCKED                             (EL_FIRST_RUNTIME_UNREAL + 0)
+#define EL_EXPLOSION                           (EL_FIRST_RUNTIME_UNREAL + 1)
+#define EL_NUT_BREAKING                                (EL_FIRST_RUNTIME_UNREAL + 2)
+#define EL_DIAMOND_BREAKING                    (EL_FIRST_RUNTIME_UNREAL + 3)
+#define EL_ACID_SPLASH_LEFT                    (EL_FIRST_RUNTIME_UNREAL + 4)
+#define EL_ACID_SPLASH_RIGHT                   (EL_FIRST_RUNTIME_UNREAL + 5)
+#define EL_AMOEBA_GROWING                      (EL_FIRST_RUNTIME_UNREAL + 6)
+#define EL_AMOEBA_SHRINKING                    (EL_FIRST_RUNTIME_UNREAL + 7)
+#define EL_EXPANDABLE_WALL_GROWING             (EL_FIRST_RUNTIME_UNREAL + 8)
+#define EL_EXPANDABLE_STEELWALL_GROWING                (EL_FIRST_RUNTIME_UNREAL + 9)
+#define EL_FLAMES                              (EL_FIRST_RUNTIME_UNREAL + 10)
+#define EL_PLAYER_IS_LEAVING                   (EL_FIRST_RUNTIME_UNREAL + 11)
+#define EL_PLAYER_IS_EXPLODING_1               (EL_FIRST_RUNTIME_UNREAL + 12)
+#define EL_PLAYER_IS_EXPLODING_2               (EL_FIRST_RUNTIME_UNREAL + 13)
+#define EL_PLAYER_IS_EXPLODING_3               (EL_FIRST_RUNTIME_UNREAL + 14)
+#define EL_PLAYER_IS_EXPLODING_4               (EL_FIRST_RUNTIME_UNREAL + 15)
+#define EL_QUICKSAND_FILLING                   (EL_FIRST_RUNTIME_UNREAL + 16)
+#define EL_QUICKSAND_FAST_FILLING              (EL_FIRST_RUNTIME_UNREAL + 17)
+#define EL_MAGIC_WALL_FILLING                  (EL_FIRST_RUNTIME_UNREAL + 18)
+#define EL_BD_MAGIC_WALL_FILLING               (EL_FIRST_RUNTIME_UNREAL + 19)
+#define EL_DC_MAGIC_WALL_FILLING               (EL_FIRST_RUNTIME_UNREAL + 20)
+#define EL_ELEMENT_SNAPPING                    (EL_FIRST_RUNTIME_UNREAL + 21)
+#define EL_DIAGONAL_SHRINKING                  (EL_FIRST_RUNTIME_UNREAL + 22)
+#define EL_DIAGONAL_GROWING                    (EL_FIRST_RUNTIME_UNREAL + 23)
+
+#define NUM_RUNTIME_ELEMENTS                   (EL_FIRST_RUNTIME_UNREAL + 24)
 
 // dummy elements (never used as game elements, only used as graphics)
-#define EL_FIRST_DUMMY                 NUM_RUNTIME_ELEMENTS
-
-#define EL_STEELWALL_TOPLEFT           (EL_FIRST_DUMMY + 0)
-#define EL_STEELWALL_TOPRIGHT          (EL_FIRST_DUMMY + 1)
-#define EL_STEELWALL_BOTTOMLEFT                (EL_FIRST_DUMMY + 2)
-#define EL_STEELWALL_BOTTOMRIGHT       (EL_FIRST_DUMMY + 3)
-#define EL_STEELWALL_HORIZONTAL                (EL_FIRST_DUMMY + 4)
-#define EL_STEELWALL_VERTICAL          (EL_FIRST_DUMMY + 5)
-#define EL_INVISIBLE_STEELWALL_TOPLEFT    (EL_FIRST_DUMMY + 6)
-#define EL_INVISIBLE_STEELWALL_TOPRIGHT           (EL_FIRST_DUMMY + 7)
-#define EL_INVISIBLE_STEELWALL_BOTTOMLEFT  (EL_FIRST_DUMMY + 8)
-#define EL_INVISIBLE_STEELWALL_BOTTOMRIGHT (EL_FIRST_DUMMY + 9)
-#define EL_INVISIBLE_STEELWALL_HORIZONTAL  (EL_FIRST_DUMMY + 10)
-#define EL_INVISIBLE_STEELWALL_VERTICAL           (EL_FIRST_DUMMY + 11)
-#define EL_DYNABOMB                    (EL_FIRST_DUMMY + 12)
-#define EL_DYNABOMB_ACTIVE             (EL_FIRST_DUMMY + 13)
-#define EL_DYNABOMB_PLAYER_1           (EL_FIRST_DUMMY + 14)
-#define EL_DYNABOMB_PLAYER_2           (EL_FIRST_DUMMY + 15)
-#define EL_DYNABOMB_PLAYER_3           (EL_FIRST_DUMMY + 16)
-#define EL_DYNABOMB_PLAYER_4           (EL_FIRST_DUMMY + 17)
-#define EL_SHIELD_NORMAL_ACTIVE                (EL_FIRST_DUMMY + 18)
-#define EL_SHIELD_DEADLY_ACTIVE                (EL_FIRST_DUMMY + 19)
-#define EL_AMOEBA                      (EL_FIRST_DUMMY + 20)
-#define EL_MM_LIGHTBALL_RED            (EL_FIRST_DUMMY + 21)
-#define EL_MM_LIGHTBALL_BLUE           (EL_FIRST_DUMMY + 22)
-#define EL_MM_LIGHTBALL_YELLOW         (EL_FIRST_DUMMY + 23)
-#define EL_MM_MASK_MCDUFFIN_RIGHT      (EL_FIRST_DUMMY + 24)
-#define EL_MM_MASK_MCDUFFIN_UP         (EL_FIRST_DUMMY + 25)
-#define EL_MM_MASK_MCDUFFIN_LEFT       (EL_FIRST_DUMMY + 26)
-#define EL_MM_MASK_MCDUFFIN_DOWN       (EL_FIRST_DUMMY + 27)
-#define EL_MM_MASK_GRID_1              (EL_FIRST_DUMMY + 28)
-#define EL_MM_MASK_GRID_2              (EL_FIRST_DUMMY + 29)
-#define EL_MM_MASK_GRID_3              (EL_FIRST_DUMMY + 30)
-#define EL_MM_MASK_GRID_4              (EL_FIRST_DUMMY + 31)
-#define EL_MM_MASK_RECTANGLE           (EL_FIRST_DUMMY + 32)
-#define EL_MM_MASK_CIRCLE              (EL_FIRST_DUMMY + 33)
-#define EL_DEFAULT                     (EL_FIRST_DUMMY + 34)
-#define EL_BD_DEFAULT                  (EL_FIRST_DUMMY + 35)
-#define EL_SP_DEFAULT                  (EL_FIRST_DUMMY + 36)
-#define EL_SB_DEFAULT                  (EL_FIRST_DUMMY + 37)
-#define EL_MM_DEFAULT                  (EL_FIRST_DUMMY + 38)
-#define EL_GRAPHIC_1                   (EL_FIRST_DUMMY + 39)
-#define EL_GRAPHIC_2                   (EL_FIRST_DUMMY + 40)
-#define EL_GRAPHIC_3                   (EL_FIRST_DUMMY + 41)
-#define EL_GRAPHIC_4                   (EL_FIRST_DUMMY + 42)
-#define EL_GRAPHIC_5                   (EL_FIRST_DUMMY + 43)
-#define EL_GRAPHIC_6                   (EL_FIRST_DUMMY + 44)
-#define EL_GRAPHIC_7                   (EL_FIRST_DUMMY + 45)
-#define EL_GRAPHIC_8                   (EL_FIRST_DUMMY + 46)
-
-#define EL_MM_DUMMY_START              EL_MM_MASK_MCDUFFIN_RIGHT
-#define EL_MM_DUMMY_END                        EL_MM_MASK_CIRCLE
+#define EL_FIRST_DUMMY                         NUM_RUNTIME_ELEMENTS
+
+#define EL_STEELWALL_TOPLEFT                   (EL_FIRST_DUMMY + 0)
+#define EL_STEELWALL_TOPRIGHT                  (EL_FIRST_DUMMY + 1)
+#define EL_STEELWALL_BOTTOMLEFT                        (EL_FIRST_DUMMY + 2)
+#define EL_STEELWALL_BOTTOMRIGHT               (EL_FIRST_DUMMY + 3)
+#define EL_STEELWALL_HORIZONTAL                        (EL_FIRST_DUMMY + 4)
+#define EL_STEELWALL_VERTICAL                  (EL_FIRST_DUMMY + 5)
+#define EL_INVISIBLE_STEELWALL_TOPLEFT         (EL_FIRST_DUMMY + 6)
+#define EL_INVISIBLE_STEELWALL_TOPRIGHT                (EL_FIRST_DUMMY + 7)
+#define EL_INVISIBLE_STEELWALL_BOTTOMLEFT      (EL_FIRST_DUMMY + 8)
+#define EL_INVISIBLE_STEELWALL_BOTTOMRIGHT     (EL_FIRST_DUMMY + 9)
+#define EL_INVISIBLE_STEELWALL_HORIZONTAL      (EL_FIRST_DUMMY + 10)
+#define EL_INVISIBLE_STEELWALL_VERTICAL                (EL_FIRST_DUMMY + 11)
+#define EL_DYNABOMB                            (EL_FIRST_DUMMY + 12)
+#define EL_DYNABOMB_ACTIVE                     (EL_FIRST_DUMMY + 13)
+#define EL_DYNABOMB_PLAYER_1                   (EL_FIRST_DUMMY + 14)
+#define EL_DYNABOMB_PLAYER_2                   (EL_FIRST_DUMMY + 15)
+#define EL_DYNABOMB_PLAYER_3                   (EL_FIRST_DUMMY + 16)
+#define EL_DYNABOMB_PLAYER_4                   (EL_FIRST_DUMMY + 17)
+#define EL_SHIELD_NORMAL_ACTIVE                        (EL_FIRST_DUMMY + 18)
+#define EL_SHIELD_DEADLY_ACTIVE                        (EL_FIRST_DUMMY + 19)
+#define EL_AMOEBA                              (EL_FIRST_DUMMY + 20)
+#define EL_MM_LIGHTBALL_RED                    (EL_FIRST_DUMMY + 21)
+#define EL_MM_LIGHTBALL_BLUE                   (EL_FIRST_DUMMY + 22)
+#define EL_MM_LIGHTBALL_YELLOW                 (EL_FIRST_DUMMY + 23)
+#define EL_DEFAULT                             (EL_FIRST_DUMMY + 24)
+#define EL_BD_DEFAULT                          (EL_FIRST_DUMMY + 25)
+#define EL_BDX_DEFAULT                         (EL_FIRST_DUMMY + 26)
+#define EL_SP_DEFAULT                          (EL_FIRST_DUMMY + 27)
+#define EL_SB_DEFAULT                          (EL_FIRST_DUMMY + 28)
+#define EL_MM_DEFAULT                          (EL_FIRST_DUMMY + 29)
+#define EL_GRAPHIC_1                           (EL_FIRST_DUMMY + 30)
+#define EL_GRAPHIC_2                           (EL_FIRST_DUMMY + 31)
+#define EL_GRAPHIC_3                           (EL_FIRST_DUMMY + 32)
+#define EL_GRAPHIC_4                           (EL_FIRST_DUMMY + 33)
+#define EL_GRAPHIC_5                           (EL_FIRST_DUMMY + 34)
+#define EL_GRAPHIC_6                           (EL_FIRST_DUMMY + 35)
+#define EL_GRAPHIC_7                           (EL_FIRST_DUMMY + 36)
+#define EL_GRAPHIC_8                           (EL_FIRST_DUMMY + 37)
+#define EL_BDX_GAME_GRAPHICS_COLOR_TEMPLATE    (EL_FIRST_DUMMY + 38)
 
 // internal elements (only used for internal purposes like copying)
-#define EL_FIRST_INTERNAL              (EL_FIRST_DUMMY + 47)
+#define EL_FIRST_INTERNAL                      (EL_FIRST_DUMMY + 39)
 
-#define EL_INTERNAL_CLIPBOARD_CUSTOM   (EL_FIRST_INTERNAL + 0)
-#define EL_INTERNAL_CLIPBOARD_CHANGE   (EL_FIRST_INTERNAL + 1)
-#define EL_INTERNAL_CLIPBOARD_GROUP    (EL_FIRST_INTERNAL + 2)
-#define EL_INTERNAL_DUMMY              (EL_FIRST_INTERNAL + 3)
+#define EL_INTERNAL_CLIPBOARD_CUSTOM           (EL_FIRST_INTERNAL + 0)
+#define EL_INTERNAL_CLIPBOARD_CHANGE           (EL_FIRST_INTERNAL + 1)
+#define EL_INTERNAL_CLIPBOARD_GROUP            (EL_FIRST_INTERNAL + 2)
+#define EL_INTERNAL_DUMMY                      (EL_FIRST_INTERNAL + 3)
 
 #define EL_INTERNAL_CASCADE_BD                 (EL_FIRST_INTERNAL + 4)
 #define EL_INTERNAL_CASCADE_BD_ACTIVE          (EL_FIRST_INTERNAL + 5)
-#define EL_INTERNAL_CASCADE_EM                 (EL_FIRST_INTERNAL + 6)
-#define EL_INTERNAL_CASCADE_EM_ACTIVE          (EL_FIRST_INTERNAL + 7)
-#define EL_INTERNAL_CASCADE_EMC                        (EL_FIRST_INTERNAL + 8)
-#define EL_INTERNAL_CASCADE_EMC_ACTIVE         (EL_FIRST_INTERNAL + 9)
-#define EL_INTERNAL_CASCADE_RND                        (EL_FIRST_INTERNAL + 10)
-#define EL_INTERNAL_CASCADE_RND_ACTIVE         (EL_FIRST_INTERNAL + 11)
-#define EL_INTERNAL_CASCADE_SB                 (EL_FIRST_INTERNAL + 12)
-#define EL_INTERNAL_CASCADE_SB_ACTIVE          (EL_FIRST_INTERNAL + 13)
-#define EL_INTERNAL_CASCADE_SP                 (EL_FIRST_INTERNAL + 14)
-#define EL_INTERNAL_CASCADE_SP_ACTIVE          (EL_FIRST_INTERNAL + 15)
-#define EL_INTERNAL_CASCADE_DC                 (EL_FIRST_INTERNAL + 16)
-#define EL_INTERNAL_CASCADE_DC_ACTIVE          (EL_FIRST_INTERNAL + 17)
-#define EL_INTERNAL_CASCADE_DX                 (EL_FIRST_INTERNAL + 18)
-#define EL_INTERNAL_CASCADE_DX_ACTIVE          (EL_FIRST_INTERNAL + 19)
-#define EL_INTERNAL_CASCADE_MM                 (EL_FIRST_INTERNAL + 20)
-#define EL_INTERNAL_CASCADE_MM_ACTIVE          (EL_FIRST_INTERNAL + 21)
-#define EL_INTERNAL_CASCADE_DF                 (EL_FIRST_INTERNAL + 22)
-#define EL_INTERNAL_CASCADE_DF_ACTIVE          (EL_FIRST_INTERNAL + 23)
-#define EL_INTERNAL_CASCADE_CHARS              (EL_FIRST_INTERNAL + 24)
-#define EL_INTERNAL_CASCADE_CHARS_ACTIVE       (EL_FIRST_INTERNAL + 25)
-#define EL_INTERNAL_CASCADE_STEEL_CHARS                (EL_FIRST_INTERNAL + 26)
-#define EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE (EL_FIRST_INTERNAL + 27)
-#define EL_INTERNAL_CASCADE_CE                 (EL_FIRST_INTERNAL + 28)
-#define EL_INTERNAL_CASCADE_CE_ACTIVE          (EL_FIRST_INTERNAL + 29)
-#define EL_INTERNAL_CASCADE_GE                 (EL_FIRST_INTERNAL + 30)
-#define EL_INTERNAL_CASCADE_GE_ACTIVE          (EL_FIRST_INTERNAL + 31)
-#define EL_INTERNAL_CASCADE_REF                        (EL_FIRST_INTERNAL + 32)
-#define EL_INTERNAL_CASCADE_REF_ACTIVE         (EL_FIRST_INTERNAL + 33)
-#define EL_INTERNAL_CASCADE_USER               (EL_FIRST_INTERNAL + 34)
-#define EL_INTERNAL_CASCADE_USER_ACTIVE                (EL_FIRST_INTERNAL + 35)
-#define EL_INTERNAL_CASCADE_DYNAMIC            (EL_FIRST_INTERNAL + 36)
-#define EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE     (EL_FIRST_INTERNAL + 37)
-
-#define EL_INTERNAL_CLIPBOARD_START    (EL_FIRST_INTERNAL + 0)
-#define EL_INTERNAL_CLIPBOARD_END      (EL_FIRST_INTERNAL + 2)
-#define EL_INTERNAL_START              (EL_FIRST_INTERNAL + 0)
-#define EL_INTERNAL_END                        (EL_FIRST_INTERNAL + 37)
-
-#define MAX_NUM_ELEMENTS               (EL_FIRST_INTERNAL + 38)
+#define EL_INTERNAL_CASCADE_BDX                        (EL_FIRST_INTERNAL + 6)
+#define EL_INTERNAL_CASCADE_BDX_ACTIVE         (EL_FIRST_INTERNAL + 7)
+#define EL_INTERNAL_CASCADE_BDX_EFFECTS                (EL_FIRST_INTERNAL + 8)
+#define EL_INTERNAL_CASCADE_BDX_EFFECTS_ACTIVE (EL_FIRST_INTERNAL + 9)
+#define EL_INTERNAL_CASCADE_EM                 (EL_FIRST_INTERNAL + 10)
+#define EL_INTERNAL_CASCADE_EM_ACTIVE          (EL_FIRST_INTERNAL + 11)
+#define EL_INTERNAL_CASCADE_EMC                        (EL_FIRST_INTERNAL + 12)
+#define EL_INTERNAL_CASCADE_EMC_ACTIVE         (EL_FIRST_INTERNAL + 13)
+#define EL_INTERNAL_CASCADE_RND                        (EL_FIRST_INTERNAL + 14)
+#define EL_INTERNAL_CASCADE_RND_ACTIVE         (EL_FIRST_INTERNAL + 15)
+#define EL_INTERNAL_CASCADE_SB                 (EL_FIRST_INTERNAL + 16)
+#define EL_INTERNAL_CASCADE_SB_ACTIVE          (EL_FIRST_INTERNAL + 17)
+#define EL_INTERNAL_CASCADE_SP                 (EL_FIRST_INTERNAL + 18)
+#define EL_INTERNAL_CASCADE_SP_ACTIVE          (EL_FIRST_INTERNAL + 19)
+#define EL_INTERNAL_CASCADE_DC                 (EL_FIRST_INTERNAL + 20)
+#define EL_INTERNAL_CASCADE_DC_ACTIVE          (EL_FIRST_INTERNAL + 21)
+#define EL_INTERNAL_CASCADE_DX                 (EL_FIRST_INTERNAL + 22)
+#define EL_INTERNAL_CASCADE_DX_ACTIVE          (EL_FIRST_INTERNAL + 23)
+#define EL_INTERNAL_CASCADE_MM                 (EL_FIRST_INTERNAL + 24)
+#define EL_INTERNAL_CASCADE_MM_ACTIVE          (EL_FIRST_INTERNAL + 25)
+#define EL_INTERNAL_CASCADE_DF                 (EL_FIRST_INTERNAL + 26)
+#define EL_INTERNAL_CASCADE_DF_ACTIVE          (EL_FIRST_INTERNAL + 27)
+#define EL_INTERNAL_CASCADE_CHARS              (EL_FIRST_INTERNAL + 28)
+#define EL_INTERNAL_CASCADE_CHARS_ACTIVE       (EL_FIRST_INTERNAL + 29)
+#define EL_INTERNAL_CASCADE_STEEL_CHARS                (EL_FIRST_INTERNAL + 30)
+#define EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE (EL_FIRST_INTERNAL + 31)
+#define EL_INTERNAL_CASCADE_CE                 (EL_FIRST_INTERNAL + 32)
+#define EL_INTERNAL_CASCADE_CE_ACTIVE          (EL_FIRST_INTERNAL + 33)
+#define EL_INTERNAL_CASCADE_GE                 (EL_FIRST_INTERNAL + 34)
+#define EL_INTERNAL_CASCADE_GE_ACTIVE          (EL_FIRST_INTERNAL + 35)
+#define EL_INTERNAL_CASCADE_ES                 (EL_FIRST_INTERNAL + 36)
+#define EL_INTERNAL_CASCADE_ES_ACTIVE          (EL_FIRST_INTERNAL + 37)
+#define EL_INTERNAL_CASCADE_REF                        (EL_FIRST_INTERNAL + 38)
+#define EL_INTERNAL_CASCADE_REF_ACTIVE         (EL_FIRST_INTERNAL + 39)
+#define EL_INTERNAL_CASCADE_USER               (EL_FIRST_INTERNAL + 40)
+#define EL_INTERNAL_CASCADE_USER_ACTIVE                (EL_FIRST_INTERNAL + 41)
+#define EL_INTERNAL_CASCADE_DYNAMIC            (EL_FIRST_INTERNAL + 42)
+#define EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE     (EL_FIRST_INTERNAL + 43)
+
+#define EL_INTERNAL_CLIPBOARD_START            (EL_FIRST_INTERNAL + 0)
+#define EL_INTERNAL_CLIPBOARD_END              (EL_FIRST_INTERNAL + 2)
+#define EL_INTERNAL_START                      (EL_FIRST_INTERNAL + 0)
+#define EL_INTERNAL_END                                (EL_FIRST_INTERNAL + 43)
+
+#define MAX_NUM_ELEMENTS                       (EL_FIRST_INTERNAL + 44)
 
 
 // values for graphics/sounds action types
@@ -2193,6 +2622,7 @@ enum
   ACTION_TWINKLING,
   ACTION_SPLASHING,
   ACTION_HITTING,
+  ACTION_FLYING,
   ACTION_PAGE_1,
   ACTION_PAGE_2,
   ACTION_PAGE_3,
@@ -2270,6 +2700,7 @@ enum
 enum
 {
   GFX_SPECIAL_ARG_DEFAULT = 0,
+  GFX_SPECIAL_ARG_LOADING_INITIAL,
   GFX_SPECIAL_ARG_LOADING,
   GFX_SPECIAL_ARG_TITLE_INITIAL,
   GFX_SPECIAL_ARG_TITLE_INITIAL_1,
@@ -2288,6 +2719,7 @@ enum
   GFX_SPECIAL_ARG_LEVELS,
   GFX_SPECIAL_ARG_LEVELNR,
   GFX_SPECIAL_ARG_SCORES,
+  GFX_SPECIAL_ARG_SCOREINFO,
   GFX_SPECIAL_ARG_EDITOR,
   GFX_SPECIAL_ARG_INFO,
   GFX_SPECIAL_ARG_SETUP,
@@ -2299,6 +2731,7 @@ enum
   GFX_SPECIAL_ARG_CRUMBLED,
   GFX_SPECIAL_ARG_MAINONLY,
   GFX_SPECIAL_ARG_NAMESONLY,
+  GFX_SPECIAL_ARG_SCORESONLY,
   GFX_SPECIAL_ARG_TYPENAME,
   GFX_SPECIAL_ARG_TYPENAMES,
   GFX_SPECIAL_ARG_SUBMENU,
@@ -2308,6 +2741,7 @@ enum
   GFX_SPECIAL_ARG_SCORESNEW,
   GFX_SPECIAL_ARG_NO_TITLE,
   GFX_SPECIAL_ARG_FADING,
+  GFX_SPECIAL_ARG_RESTARTING,
   GFX_SPECIAL_ARG_QUIT,
 
   NUM_SPECIAL_GFX_ARGS
@@ -2348,6 +2782,7 @@ enum
   GFX_SPECIAL_ARG_SETUP_SHORTCUTS_3,
   GFX_SPECIAL_ARG_SETUP_SHORTCUTS_4,
   GFX_SPECIAL_ARG_SETUP_SHORTCUTS_5,
+  GFX_SPECIAL_ARG_SETUP_SHORTCUTS_6,
   GFX_SPECIAL_ARG_SETUP_CHOOSE_ARTWORK,
   GFX_SPECIAL_ARG_SETUP_CHOOSE_OTHER,
 
@@ -2379,6 +2814,7 @@ enum
   GFX_ARG_DELAY,
   GFX_ARG_ANIM_MODE,
   GFX_ARG_GLOBAL_SYNC,
+  GFX_ARG_GLOBAL_ANIM_SYNC,
   GFX_ARG_CRUMBLED_LIKE,
   GFX_ARG_DIGGABLE_LIKE,
   GFX_ARG_BORDER_SIZE,
@@ -2419,10 +2855,15 @@ enum
   GFX_ARG_SORT_PRIORITY,
   GFX_ARG_CLASS,
   GFX_ARG_STYLE,
+  GFX_ARG_ALPHA,
   GFX_ARG_ACTIVE_XOFFSET,
   GFX_ARG_ACTIVE_YOFFSET,
   GFX_ARG_PRESSED_XOFFSET,
   GFX_ARG_PRESSED_YOFFSET,
+  GFX_ARG_STACKED_XFACTOR,
+  GFX_ARG_STACKED_YFACTOR,
+  GFX_ARG_STACKED_XOFFSET,
+  GFX_ARG_STACKED_YOFFSET,
 
   NUM_GFX_ARGS
 };
@@ -2470,6 +2911,7 @@ enum
   FONT_ENVELOPE_2,
   FONT_ENVELOPE_3,
   FONT_ENVELOPE_4,
+  FONT_REQUEST_NARROW,
   FONT_REQUEST,
   FONT_INPUT_1_ACTIVE,
   FONT_INPUT_2_ACTIVE,
@@ -2521,6 +2963,7 @@ enum
 
 // values for game_status (must match special image configuration suffixes)
 #define GAME_MODE_DEFAULT              GFX_SPECIAL_ARG_DEFAULT
+#define GAME_MODE_LOADING_INITIAL      GFX_SPECIAL_ARG_LOADING_INITIAL
 #define GAME_MODE_LOADING              GFX_SPECIAL_ARG_LOADING
 #define GAME_MODE_TITLE_INITIAL                GFX_SPECIAL_ARG_TITLE_INITIAL
 #define GAME_MODE_TITLE_INITIAL_1      GFX_SPECIAL_ARG_TITLE_INITIAL_1
@@ -2539,6 +2982,7 @@ enum
 #define GAME_MODE_LEVELS               GFX_SPECIAL_ARG_LEVELS
 #define GAME_MODE_LEVELNR              GFX_SPECIAL_ARG_LEVELNR
 #define GAME_MODE_SCORES               GFX_SPECIAL_ARG_SCORES
+#define GAME_MODE_SCOREINFO            GFX_SPECIAL_ARG_SCOREINFO
 #define GAME_MODE_EDITOR               GFX_SPECIAL_ARG_EDITOR
 #define GAME_MODE_INFO                 GFX_SPECIAL_ARG_INFO
 #define GAME_MODE_SETUP                        GFX_SPECIAL_ARG_SETUP
@@ -2550,6 +2994,7 @@ enum
 #define GAME_MODE_PSEUDO_CRUMBLED      GFX_SPECIAL_ARG_CRUMBLED
 #define GAME_MODE_PSEUDO_MAINONLY      GFX_SPECIAL_ARG_MAINONLY
 #define GAME_MODE_PSEUDO_NAMESONLY     GFX_SPECIAL_ARG_NAMESONLY
+#define GAME_MODE_PSEUDO_SCORESONLY    GFX_SPECIAL_ARG_SCORESONLY
 #define GAME_MODE_PSEUDO_TYPENAME      GFX_SPECIAL_ARG_TYPENAME
 #define GAME_MODE_PSEUDO_TYPENAMES     GFX_SPECIAL_ARG_TYPENAMES
 #define GAME_MODE_PSEUDO_SUBMENU       GFX_SPECIAL_ARG_SUBMENU
@@ -2559,6 +3004,7 @@ enum
 #define GAME_MODE_PSEUDO_SCORESNEW     GFX_SPECIAL_ARG_SCORESNEW
 #define GAME_MODE_PSEUDO_NO_TITLE      GFX_SPECIAL_ARG_NO_TITLE
 #define GAME_MODE_PSEUDO_FADING                GFX_SPECIAL_ARG_FADING
+#define GAME_MODE_PSEUDO_RESTARTING    GFX_SPECIAL_ARG_RESTARTING
 #define GAME_MODE_QUIT                 GFX_SPECIAL_ARG_QUIT
 
 #define NUM_GAME_MODES                 NUM_SPECIAL_GFX_ARGS
@@ -2574,19 +3020,19 @@ enum
 
 // program information and versioning definitions
 #define PROGRAM_VERSION_SUPER          4
-#define PROGRAM_VERSION_MAJOR          3
+#define PROGRAM_VERSION_MAJOR          4
 #define PROGRAM_VERSION_MINOR          0
 #define PROGRAM_VERSION_PATCH          0
-#define PROGRAM_VERSION_EXTRA          ""
+#define PROGRAM_VERSION_EXTRA          "-test-1"
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
 #define PROGRAM_EMAIL_STRING           "info@artsoft.org"
 #define PROGRAM_WEBSITE_STRING         "https://www.artsoft.org/"
-#define PROGRAM_COPYRIGHT_STRING       "Copyright \xa9""1995-2021 by Holger Schemel"
+#define PROGRAM_COPYRIGHT_STRING       "1995-2024 by Holger Schemel"
 #define PROGRAM_COMPANY_STRING         "A Game by Artsoft Entertainment"
 
-#define PROGRAM_ICON_FILENAME          "RocksIcon32x32.png"
+#define PROGRAM_ICON_FILENAME          "icons/icon.png"
 
 #define COOKIE_PREFIX                  "ROCKSNDIAMONDS"
 
@@ -2643,11 +3089,12 @@ enum
 // values for game engine type identifier
 #define GAME_ENGINE_TYPE_UNKNOWN       LEVEL_FILE_TYPE_UNKNOWN
 #define GAME_ENGINE_TYPE_RND           LEVEL_FILE_TYPE_RND
+#define GAME_ENGINE_TYPE_BD            LEVEL_FILE_TYPE_BD
 #define GAME_ENGINE_TYPE_EM            LEVEL_FILE_TYPE_EM
 #define GAME_ENGINE_TYPE_SP            LEVEL_FILE_TYPE_SP
 #define GAME_ENGINE_TYPE_MM            LEVEL_FILE_TYPE_MM
 
-#define NUM_ENGINE_TYPES               4
+#define NUM_ENGINE_TYPES               5
 
 // values for automatically playing tapes
 #define AUTOPLAY_NONE                  0
@@ -2714,6 +3161,7 @@ struct MenuMainButtonInfo
   struct MenuPosInfo insert_solution;
   struct MenuPosInfo play_solution;
 
+  struct MenuPosInfo levelset_info;
   struct MenuPosInfo switch_ecs_aga;
 };
 
@@ -2775,6 +3223,20 @@ struct MenuSetupInfo
   struct MenuSetupButtonInfo button;
 };
 
+struct MenuScoresButtonInfo
+{
+  struct MenuPosInfo prev_level;
+  struct MenuPosInfo next_level;
+  struct MenuPosInfo prev_score;
+  struct MenuPosInfo next_score;
+  struct MenuPosInfo play_tape;
+};
+
+struct MenuScoresInfo
+{
+  struct MenuScoresButtonInfo button;
+};
+
 struct TitleFadingInfo
 {
   int fade_mode;
@@ -2805,7 +3267,9 @@ struct TitleMessageInfo
 
 struct InitInfo
 {
+  struct MenuPosInfo busy_initial;
   struct MenuPosInfo busy;
+  struct MenuPosInfo busy_playfield;
 };
 
 struct MenuInfo
@@ -2823,10 +3287,13 @@ struct MenuInfo
 
   int list_size[NUM_SPECIAL_GFX_ARGS];
   int list_size_info[NUM_SPECIAL_GFX_INFO_ARGS];
+  int list_entry_size_info[NUM_SPECIAL_GFX_INFO_ARGS];
+  int tile_size_info[NUM_SPECIAL_GFX_INFO_ARGS];
 
   int left_spacing[NUM_SPECIAL_GFX_ARGS];
   int left_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS];
   int left_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS];
+  int middle_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS];
   int right_spacing[NUM_SPECIAL_GFX_ARGS];
   int right_spacing_info[NUM_SPECIAL_GFX_INFO_ARGS];
   int right_spacing_setup[NUM_SPECIAL_GFX_SETUP_ARGS];
@@ -2864,6 +3331,7 @@ struct MenuInfo
 
   struct MenuMainInfo main;
   struct MenuSetupInfo setup;
+  struct MenuScoresInfo scores;
 };
 
 struct DoorInfo
@@ -3048,6 +3516,14 @@ struct ScoreEntry
   char name[MAX_PLAYER_NAME_LEN + 1];
   int score;
   int time;            // time (in frames) or steps played
+
+  // additional score information for score info screen
+  int id;
+  char tape_date[MAX_ISO_DATE_LEN + 1];
+  char platform[MAX_PLATFORM_TEXT_LEN + 1];
+  char version[MAX_VERSION_TEXT_LEN + 1];
+  char country_code[MAX_COUNTRY_CODE_LEN + 1];
+  char country_name[MAX_COUNTRY_NAME_LEN + 1];
 };
 
 struct ScoreInfo
@@ -3061,10 +3537,16 @@ struct ScoreInfo
   int num_entries;
   int last_added;
   int last_added_local;
+  int last_level_nr;
+  int last_entry_nr;
+  int next_level_nr;
 
   boolean updated;
   boolean uploaded;
+  boolean tape_downloaded;
   boolean force_last_added;
+  boolean continue_playing;
+  boolean continue_on_return;
 
   struct ScoreEntry entry[MAX_SCORE_ENTRIES];
 };
@@ -3114,12 +3596,13 @@ struct LevelInfo
   int game_engine_type;
 
   // level stored in native format for the alternative native game engines
+  struct LevelInfo_BD *native_bd_level;
   struct LevelInfo_EM *native_em_level;
   struct LevelInfo_SP *native_sp_level;
   struct LevelInfo_MM *native_mm_level;
 
-  int file_version;    // file format version the level is stored with
-  int game_version;    // game release version the level was created with
+  int file_version;                    // file format version the level is stored with
+  int game_version;                    // game release version the level was created with
 
   struct DateInfo creation_date;
 
@@ -3193,8 +3676,8 @@ struct LevelInfo
   int num_android_clone_elements;
   int android_clone_element[MAX_ANDROID_ELEMENTS];
 
-  int can_move_into_acid_bits; // bitfield to store property for elements
-  int dont_collide_with_bits;  // bitfield to store property for elements
+  int can_move_into_acid_bits;         // bitfield to store property for elements
+  int dont_collide_with_bits;          // bitfield to store property for elements
 
   int initial_player_stepsize[MAX_PLAYERS];    // initial player speed
   boolean initial_player_gravity[MAX_PLAYERS];
@@ -3203,27 +3686,140 @@ struct LevelInfo
   int initial_inventory_size[MAX_PLAYERS];
   int initial_inventory_content[MAX_PLAYERS][MAX_INITIAL_INVENTORY_SIZE];
 
-  boolean em_slippery_gems;    // EM style "gems slip from wall" behaviour
-  boolean em_explodes_by_fire; // EM style chain explosion behaviour
-  boolean use_spring_bug;      // for compatibility with old levels
-  boolean use_time_orb_bug;    // for compatibility with old levels
-  boolean use_life_bugs;       // for compatibility with old levels
-  boolean instant_relocation;  // no visual delay when relocating player
-  boolean shifted_relocation;  // no level centering when relocating player
-  boolean lazy_relocation;     // only redraw off-screen player relocation
-  boolean can_pass_to_walkable;        // player can pass to empty or walkable tile
-  boolean grow_into_diggable;  // amoeba can grow into anything diggable
-  boolean sb_fields_needed;    // all Sokoban fields must be solved
-  boolean sb_objects_needed;   // all Sokoban objects must be solved
-  boolean auto_exit_sokoban;   // automatically finish solved Sokoban levels
-  boolean solved_by_one_player;        // level is solved if one player enters exit
-  boolean finish_dig_collect;  // only finished dig/collect triggers ce action
-  boolean keep_walkable_ce;    // keep walkable CE if it changes to the player
-
-  boolean continuous_snapping; // repeated snapping without releasing key
-  boolean block_snap_field;    // snapping blocks field to show animation
-  boolean block_last_field;    // player blocks previous field while moving
-  boolean sp_block_last_field; // player blocks previous field while moving
+  int bd_cycle_delay_ms;               // BD game cycle delay (in milliseconds)
+  int bd_cycle_delay_c64;              // BD game cycle delay (in C64 game units)
+  int bd_hatching_delay_cycles;                // BD hatching delay (in game cycles)
+  int bd_hatching_delay_seconds;       // BD hatching delay (in seconds)
+  int bd_scheduling_type;              // BD engine scheduling type
+  boolean bd_pal_timing;               // BD engine uses special PAL timing
+  boolean bd_line_shifting_borders;    // BD engine uses line-shifting wrap-around
+  boolean bd_scan_first_and_last_row;  // BD engine scans top and bottom border rows
+  boolean bd_short_explosions;         // BD engine uses four game cycles for explosions
+  boolean bd_intermission;             // BD level is intermission
+  boolean bd_diagonal_movements;       // BD style diagonal movements
+  boolean bd_topmost_player_active;    // BD engine uses first player found on playfield
+  int bd_snap_element;                 // BD element that is created when player is snapping
+  int bd_pushing_prob;                 // BD player probability to push rocks
+  int bd_pushing_prob_with_sweet;      // BD player probability to push rocks after eating sweet
+  boolean bd_push_mega_rock_with_sweet;        // BD player can push mega rocks after eating sweet
+  boolean bd_magic_wall_zero_infinite; // BD magic wall with timer of zero runs infinitely
+  boolean bd_magic_wall_wait_hatching; // BD magic wall waits for player's birth
+  boolean bd_magic_wall_stops_amoeba;  // BD magic wall can stop amoeba and turn to diamonds
+  boolean bd_magic_wall_break_scan;    // BD magic wall setting to implement buggy BD1 behaviour
+  int bd_magic_wall_time;              // BD magic wall time
+  int bd_magic_wall_diamond_to;                // BD magic wall turns diamonds to specified element
+  int bd_magic_wall_rock_to;           // BD magic wall turns rocks to specified element
+  int bd_magic_wall_mega_rock_to;      // BD magic wall turns mega rocks to specified element
+  int bd_magic_wall_nut_to;            // BD magic wall turns nuts to specified element
+  int bd_magic_wall_nitro_pack_to;     // BD magic wall turns nitro packs to specified element
+  int bd_magic_wall_flying_diamond_to; // BD magic wall turns flying diamonds to specified element
+  int bd_magic_wall_flying_rock_to;    // BD magic wall turns flying rocks to specified element
+  boolean bd_amoeba_wait_for_hatching; // BD amoeba waits for player's birth
+  boolean bd_amoeba_start_immediately; // BD amoeba growth starts immediately
+  boolean bd_amoeba_2_explode_by_amoeba;// BD amoeba 2 explodes if touched by BD amoeba
+  int bd_amoeba_1_threshold_too_big;   // BD amoeba 1 turns to stones if threshold reached
+  int bd_amoeba_1_slow_growth_time;    // BD amoeba 1 slow growth time (in seconds)
+  int bd_amoeba_1_slow_growth_rate;    // BD amoeba 1 slow growth rate (in percent)
+  int bd_amoeba_1_fast_growth_rate;    // BD amoeba 1 fast growth rate (in percent)
+  int bd_amoeba_1_content_too_big;     // BD amoeba 1 changes to this element if too big
+  int bd_amoeba_1_content_enclosed;    // BD amoeba 1 changes to this element if enclosed
+  int bd_amoeba_2_threshold_too_big;   // BD amoeba 2 turns to stones if threshold reached
+  int bd_amoeba_2_slow_growth_time;    // BD amoeba 2 slow growth time (in seconds)
+  int bd_amoeba_2_slow_growth_rate;    // BD amoeba 2 slow growth rate (in percent)
+  int bd_amoeba_2_fast_growth_rate;    // BD amoeba 2 fast growth rate (in percent)
+  int bd_amoeba_2_content_too_big;     // BD amoeba 2 changes to this element if too big
+  int bd_amoeba_2_content_enclosed;    // BD amoeba 2 changes to this element if enclosed
+  int bd_amoeba_2_content_exploding;   // BD amoeba 2 changes to this element if exploding
+  int bd_amoeba_2_content_looks_like;  // BD amoeba 2 looks like this other game element
+  int bd_clock_extra_time;             // BD engine extra time when collecting clock
+  boolean bd_voodoo_collects_diamonds; // BD voodoo doll can collect diamonds for the player
+  boolean bd_voodoo_hurt_kills_player; // BD voodoo doll hurt in any way, player is killed
+  boolean bd_voodoo_dies_by_rock;      // BD voodoo doll can be killed by a falling rock
+  boolean bd_voodoo_vanish_by_explosion;// BD voodoo doll can be destroyed by explosions
+  int bd_voodoo_penalty_time;          // BD engine penalty time when voodoo doll destroyed
+  boolean bd_slime_is_predictable;     // BD slime uses predictable random number generator
+  boolean bd_slime_correct_random;     // BD slime needs corrected random number generator
+  int bd_slime_permeability_rate;      // BD slime permeability rate for unpredictable slime
+  int bd_slime_permeability_bits_c64;  // BD slime permeability bits for predictable slime
+  int bd_slime_random_seed_c64;                // BD slime random number seed for predictable slime
+  int bd_slime_eats_element_1;         // BD slime can eat and convert this game element
+  int bd_slime_converts_to_element_1;  // BD slime can convert eaten element to this game element
+  int bd_slime_eats_element_2;         // BD slime can eat and convert this game element
+  int bd_slime_converts_to_element_2;  // BD slime can convert eaten element to this game element
+  int bd_slime_eats_element_3;         // BD slime can eat and convert this game element
+  int bd_slime_converts_to_element_3;  // BD slime can convert eaten element to this game element
+  int bd_cave_random_seed_c64;         // BD cave random number seed for predictable slime
+  int bd_acid_eats_element;            // BD acid eats this game element when spreading
+  int bd_acid_spread_rate;             // BD acid probability of spreading (in percent)
+  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
+  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_conveyor_belts_active;    // BD conveyor belts start in active state if enabled
+  boolean bd_conveyor_belts_changed;   // BD conveyor belts direction is changed if enabled
+  boolean bd_water_cannot_flow_down;   // BD water does not flow downwards if enabled
+  int bd_nut_content;                  // BD nut contains the specified game element
+  int bd_hammer_walls_break_delay;     // BD hammer time for breaking walls (in BD frames)
+  boolean bd_hammer_walls_reappear;    // BD hammered walls are reappearing after some delay
+  int bd_hammer_walls_reappear_delay;  // BD hammer time for reappearing walls (in BD frames)
+  boolean bd_infinite_rockets;         // BD rocket launcher has infinite number of rockets
+  int bd_num_skeletons_needed_for_pot; // BD skeletons amount must be collected to use a pot
+  int bd_skeleton_worth_num_diamonds;  // BD skeleton collected is worth this number of diamonds
+  int bd_expanding_wall_looks_like;    // BD expanding wall looks like this other game element
+  int bd_sand_looks_like;              // BD sand looks like this other game element
+  boolean bd_creatures_start_backwards;        // BD creatures start moving in opposite direction
+  boolean bd_creatures_turn_on_hatching;// BD creatures change direction after hatching
+  int bd_creatures_auto_turn_delay;    // BD creatures change direction after delay (in seconds)
+  int bd_gravity_direction;            // BD engine initial gravity direction
+  boolean bd_gravity_switch_active;    // BD engine gravity switch starts in active state
+  int bd_gravity_switch_delay;         // BD engine gravity change delay for switch (in seconds)
+  boolean bd_gravity_affects_all;      // BD engine gravity affects all falling objects
+  int bd_rock_turns_to_on_falling;     // BD rock changes to specified element when falling
+  int bd_rock_turns_to_on_impact;      // BD rock changes to specified element on impact
+  int bd_diamond_turns_to_on_falling;  // BD diamond changes to specified element when falling
+  int bd_diamond_turns_to_on_impact;   // BD diamond changes to specified element on impact
+  int bd_firefly_1_explodes_to;                // BD firefly 1 explodes to specified element
+  int bd_firefly_2_explodes_to;                // BD firefly 2 explodes to specified element
+  int bd_butterfly_1_explodes_to;      // BD butterfly 1 explodes to specified element
+  int bd_butterfly_2_explodes_to;      // BD butterfly 2 explodes to specified element
+  int bd_stonefly_explodes_to;         // BD stonefly explodes to specified element
+  int bd_dragonfly_explodes_to;                // BD dragonfly explodes to specified element
+  int bd_diamond_birth_turns_to;       // BD diamond birth changes to specified element
+  int bd_bomb_explosion_turns_to;      // BD bomb explosion changes to specified element
+  int bd_nitro_explosion_turns_to;     // BD nitro pack explosion changes to specified element
+  int bd_explosion_turns_to;           // BD other explosions change to specified element
+  int bd_color_b;                      // BD engine C64-style cave color (border)
+  int bd_color_0;                      // BD engine C64-style cave color (background)
+  int bd_color_1;                      // BD engine C64-style cave color (sand)
+  int bd_color_2;                      // BD engine C64-style cave color (steel wall)
+  int bd_color_3;                      // BD engine C64-style cave color (wall)
+  int bd_color_4;                      // BD engine C64-style cave color (amoeba)
+  int bd_color_5;                      // BD engine C64-style cave color (slime)
+
+  boolean em_slippery_gems;            // EM style "gems slip from wall" behaviour
+  boolean em_explodes_by_fire;         // EM style chain explosion behaviour
+  boolean use_spring_bug;              // for compatibility with old levels
+  boolean use_time_orb_bug;            // for compatibility with old levels
+  boolean use_life_bugs;               // for compatibility with old levels
+  boolean instant_relocation;          // no visual delay when relocating player
+  boolean shifted_relocation;          // no level centering when relocating player
+  boolean lazy_relocation;             // only redraw off-screen player relocation
+  boolean can_pass_to_walkable;                // player can pass to empty or walkable tile
+  boolean grow_into_diggable;          // amoeba can grow into anything diggable
+  boolean sb_fields_needed;            // all Sokoban fields must be solved
+  boolean sb_objects_needed;           // all Sokoban objects must be solved
+  boolean auto_exit_sokoban;           // automatically finish solved Sokoban levels
+  boolean solved_by_one_player;                // level is solved if one player enters exit
+  boolean finish_dig_collect;          // only finished dig/collect triggers ce action
+  boolean keep_walkable_ce;            // keep walkable CE if it changes to the player
+
+  boolean continuous_snapping;         // repeated snapping without releasing key
+  boolean block_snap_field;            // snapping blocks field to show animation
+  boolean block_last_field;            // player blocks previous field while moving
+  boolean sp_block_last_field;         // player blocks previous field while moving
 
   // values for MM/DF elements
   boolean mm_laser_red, mm_laser_green, mm_laser_blue;
@@ -3233,21 +3829,29 @@ struct LevelInfo
   int mm_time_ball;
   int mm_time_block;
 
+  int num_mm_ball_contents;
+  int mm_ball_choice_mode;
+  int mm_ball_content[MAX_MM_BALL_CONTENTS];
+  boolean rotate_mm_ball_content;
+  boolean explode_mm_ball;
+
   // ('int' instead of 'boolean' because used as selectbox value in editor)
-  int use_step_counter;                // count steps instead of seconds for level
+  int use_step_counter;                        // count steps instead of seconds for level
 
-  int time_score_base;         // use time score for 1 or 10 seconds/steps
+  int time_score_base;                 // use time score for 1 or 10 seconds/steps
 
   short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
-  boolean use_custom_template; // use custom properties from template file
+  boolean use_custom_template;         // use custom properties from template file
 
   boolean file_has_custom_elements;    // set when level file contains CEs
 
-  boolean no_valid_file;       // set when level file missing or invalid
-  boolean no_level_file;       // set when falling back to level template
+  int bd_color_type;                   // set according to BD colors in level
 
-  boolean changed;             // set when level was changed in the editor
+  boolean no_valid_file;               // set when level file missing or invalid
+  boolean no_level_file;               // set when falling back to level template
+
+  boolean changed;                     // set when level was changed in the editor
 
   // runtime flags to handle bugs in old levels (not stored in level file)
   boolean use_action_after_change_bug;
@@ -3280,6 +3884,8 @@ struct GlobalInfo
   char *convert_leveldir;
   int convert_level_nr;
 
+  char *dumplevelset_leveldir;
+
   char *dumplevel_leveldir;
   int dumplevel_level_nr;
 
@@ -3308,40 +3914,40 @@ struct GlobalInfo
 
 struct ElementChangeInfo
 {
-  boolean can_change;          // use or ignore this change info
+  boolean can_change;                  // use or ignore this change info
 
-  boolean has_event[NUM_CHANGE_EVENTS];                // change events
+  boolean has_event[NUM_CHANGE_EVENTS];        // change events
 
-  int trigger_player;          // player triggering change
-  int trigger_side;            // side triggering change
-  int trigger_page;            // page triggering change
+  int trigger_player;                  // player triggering change
+  int trigger_side;                    // side triggering change
+  int trigger_page;                    // page triggering change
 
-  int target_element;          // target element after change
+  int target_element;                  // target element after change
 
-  int delay_fixed;             // added frame delay before changed (fixed)
-  int delay_random;            // added frame delay before changed (random)
-  int delay_frames;            // either 1 (frames) or 50 (seconds; 50 fps)
+  int delay_fixed;                     // added frame delay before changed (fixed)
+  int delay_random;                    // added frame delay before changed (random)
+  int delay_frames;                    // either 1 (frames) or 50 (seconds; 50 fps)
 
-  int initial_trigger_element; // initial element triggering change
+  int initial_trigger_element;         // initial element triggering change
 
-  struct Content target_content;// elements for extended change target
-  boolean use_target_content;  // use extended change target
-  boolean only_if_complete;    // only use complete target content
-  boolean use_random_replace;  // use random value for replacing elements
-  int random_percentage;       // random value for replacing elements
-  int replace_when;            // type of elements that can be replaced
+  struct Content target_content;       // elements for extended change target
+  boolean use_target_content;          // use extended change target
+  boolean only_if_complete;            // only use complete target content
+  boolean use_random_replace;          // use random value for replacing elements
+  int random_percentage;               // random value for replacing elements
+  int replace_when;                    // type of elements that can be replaced
 
-  boolean explode;             // explode instead of change
+  boolean explode;                     // explode instead of change
 
-  boolean has_action;          // execute action on specified condition
-  int action_type;             // type of action
-  int action_mode;             // mode of action
-  int action_arg;              // parameter of action
-  int action_element;          // element related to action
+  boolean has_action;                  // execute action on specified condition
+  int action_type;                     // type of action
+  int action_mode;                     // mode of action
+  int action_arg;                      // parameter of action
+  int action_element;                  // element related to action
 
   // ---------- internal values used at runtime when playing ----------
 
-  int trigger_element;         // element triggering change
+  int trigger_element;                 // element triggering change
 
   /* functions that are called before, while and after the change of an
      element -- currently only used for non-custom elements */
@@ -3349,19 +3955,21 @@ struct ElementChangeInfo
   void (*change_function)(int x, int y);
   void (*post_change_function)(int x, int y);
 
-  short actual_trigger_element;        // element that actually triggered change
-  int actual_trigger_side;     // element side that triggered the change
-  int actual_trigger_player;   // player which actually triggered change
-  int actual_trigger_player_bits; // player bits of triggering players
-  int actual_trigger_ce_value; // CE value of element that triggered change
-  int actual_trigger_ce_score; // CE score of element that triggered change
+  short actual_trigger_element;                // element that actually triggered change
+  int actual_trigger_x;                        // element x position that triggered change
+  int actual_trigger_y;                        // element y position that triggered change
+  int actual_trigger_side;             // element side that triggered the change
+  int actual_trigger_player;           // player which actually triggered change
+  int actual_trigger_player_bits;      // player bits of triggering players
+  int actual_trigger_ce_value;         // CE value of element that triggered change
+  int actual_trigger_ce_score;         // CE score of element that triggered change
 
   boolean can_change_or_has_action;    // can_change | has_action
 
   // ---------- internal values used in level editor ----------
 
-  int direct_action;           // change triggered by actions on element
-  int other_action;            // change triggered by other element actions
+  int direct_action;                   // change triggered by actions on element
+  int other_action;                    // change triggered by other element actions
 };
 
 struct ElementGroupInfo
@@ -3369,7 +3977,7 @@ struct ElementGroupInfo
   int num_elements;                    // number of elements in this group
   int element[MAX_ELEMENTS_IN_GROUP];  // list of elements in this group
 
-  int choice_mode;             // how to choose element from group
+  int choice_mode;                     // how to choose element from group
 
   // ---------- internal values used at runtime when playing ----------
 
@@ -3378,92 +3986,94 @@ struct ElementGroupInfo
   int num_elements_resolved;
   short element_resolved[NUM_FILE_ELEMENTS];
 
-  int choice_pos;              // current element choice position
+  int choice_pos;                      // current element choice position
 };
 
 struct ElementNameInfo
 {
   // ---------- token and description strings ----------
 
-  char *token_name;            // element token used in config files
-  char *class_name;            // element class used in config files
-  char *editor_description;    // pre-defined description for level editor
+  char *token_name;                    // element token used in config files
+  char *class_name;                    // element class used in config files
+  char *editor_description;            // pre-defined description for level editor
 };
 
 struct ElementInfo
 {
   // ---------- token and description strings ----------
 
-  char *token_name;            // element token used in config files
-  char *class_name;            // element class used in config files
-  char *editor_description;    // pre-defined description for level editor
-  char *custom_description;    // alternative description from config file
+  char *token_name;                    // element token used in config files
+  char *class_name;                    // element class used in config files
+  char *editor_description;            // pre-defined description for level editor
+  char *custom_description;            // alternative description from config file
   char description[MAX_ELEMENT_NAME_LEN + 1];  // for custom/group elements
 
   // ---------- graphic and sound definitions ----------
 
-  int graphic[NUM_ACTIONS];    // default graphics for several actions
+  int graphic[NUM_ACTIONS];            // default graphics for several actions
   int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS_FULL];
-                               // special graphics for left/right/up/down
+                                       // special graphics for left/right/up/down
 
-  int crumbled[NUM_ACTIONS];   // crumbled graphics for several actions
+  int crumbled[NUM_ACTIONS];           // crumbled graphics for several actions
   int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS_FULL];
-                               // crumbled graphics for left/right/up/down
+                                       // crumbled graphics for left/right/up/down
 
   int special_graphic[NUM_SPECIAL_GFX_ARGS];
-                               // special graphics for certain screens
+                                       // special graphics for certain screens
 
-  int sound[NUM_ACTIONS];      // default sounds for several actions
+  int sound[NUM_ACTIONS];              // default sounds for several actions
 
   // ---------- special element property values ----------
 
   unsigned int properties[NUM_EP_BITFIELDS];   // element base properties
 
-  boolean use_gfx_element;     // use custom graphic element
-  int gfx_element_initial;     // initial optional custom graphic element
+  boolean use_gfx_element;             // use custom graphic element
+  int gfx_element_initial;             // initial optional custom graphic element
 
-  int access_direction;                // accessible from which direction
+  int access_direction;                        // accessible from which direction
 
-  int collect_score_initial;   // initial score value for collecting
-  int collect_count_initial;   // initial count value for collecting
+  int collect_score_initial;           // initial score value for collecting
+  int collect_count_initial;           // initial count value for collecting
 
-  int ce_value_fixed_initial;  // initial value for custom variable (fix)
-  int ce_value_random_initial; // initial value for custom variable (rnd)
-  boolean use_last_ce_value;   // use value from element before change
+  int ce_value_fixed_initial;          // initial value for custom variable (fix)
+  int ce_value_random_initial;         // initial value for custom variable (rnd)
+  boolean use_last_ce_value;           // use value from element before change
 
-  int push_delay_fixed;                // constant delay before pushing
-  int push_delay_random;       // additional random delay before pushing
-  int drop_delay_fixed;                // constant delay after dropping
-  int drop_delay_random;       // additional random delay after dropping
-  int move_delay_fixed;                // constant delay after moving
-  int move_delay_random;       // additional random delay after moving
-  int step_delay_fixed;                // constant delay while moving
-  int step_delay_random;       // additional random delay while moving
+  int push_delay_fixed;                        // constant delay before pushing
+  int push_delay_random;               // additional random delay before pushing
+  int drop_delay_fixed;                        // constant delay after dropping
+  int drop_delay_random;               // additional random delay after dropping
+  int move_delay_fixed;                        // constant delay after moving
+  int move_delay_random;               // additional random delay after moving
+  int step_delay_fixed;                        // constant delay while moving
+  int step_delay_random;               // additional random delay while moving
 
-  int move_pattern;            // direction movable element moves to
-  int move_direction_initial;  // initial direction element moves to
-  int move_stepsize;           // step size element moves with
+  int move_pattern;                    // direction movable element moves to
+  int move_direction_initial;          // initial direction element moves to
+  int move_stepsize;                   // step size element moves with
 
-  int move_enter_element;      // element that can be entered (and removed)
-  int move_leave_element;      // element that can be left behind
-  int move_leave_type;         // change (limited) or leave (unlimited)
+  int move_enter_element;              // element that can be entered (and removed)
+  int move_leave_element;              // element that can be left behind
+  int move_leave_type;                 // change (limited) or leave (unlimited)
 
-  int slippery_type;           // how/where other elements slip away
+  int slippery_type;                   // how/where other elements slip away
 
-  struct Content content;      // new elements after explosion
+  struct Content content;              // new elements after explosion
 
-  int explosion_type;          // type of explosion, like 3x3, 3+3 or 1x1
-  int explosion_delay;         // duration of explosion of this element
-  int ignition_delay;          // delay for explosion by other explosion
+  int explosion_type;                  // type of explosion, like 3x3, 3+3 or 1x1
+  int explosion_delay;                 // duration of explosion of this element
+  int ignition_delay;                  // delay for explosion by other explosion
 
   struct ElementChangeInfo *change_page; // actual list of change pages
   struct ElementChangeInfo *change;     // pointer to current change page
 
-  int num_change_pages;                // actual number of change pages
-  int current_change_page;     // currently edited change page
+  int num_change_pages;                        // actual number of change pages
+  int current_change_page;             // currently edited change page
 
   struct ElementGroupInfo *group;      // pointer to element group info
 
+  boolean has_anim_event;              // element can trigger global animation
+
   // ---------- internal values used at runtime when playing ----------
 
   boolean has_change_event[NUM_CHANGE_EVENTS];
@@ -3473,48 +4083,48 @@ struct ElementInfo
 
   boolean in_group[NUM_GROUP_ELEMENTS];
 
-  int gfx_element;             // runtime optional custom graphic element
+  int gfx_element;                     // runtime optional custom graphic element
 
-  int collect_score;           // runtime score value for collecting
+  int collect_score;                   // runtime score value for collecting
 
   // count of this element on playfield, calculated after each frame
   int element_count;
 
   // ---------- internal values used in level editor ----------
 
-  int access_type;             // walkable or passable
-  int access_layer;            // accessible over/inside/under
-  int access_protected;                // protection against deadly elements
-  int walk_to_action;          // diggable/collectible/pushable
-  int smash_targets;           // can smash player/enemies/everything
-  int deadliness;              // deadly when running/colliding/touching
+  int access_type;                     // walkable or passable
+  int access_layer;                    // accessible over/inside/under
+  int access_protected;                        // protection against deadly elements
+  int walk_to_action;                  // diggable/collectible/pushable
+  int smash_targets;                   // can smash player/enemies/everything
+  int deadliness;                      // deadly when running/colliding/touching
 
-  boolean can_explode_by_fire; // element explodes by fire
-  boolean can_explode_smashed; // element explodes when smashed
-  boolean can_explode_impact;  // element explodes on impact
+  boolean can_explode_by_fire;         // element explodes by fire
+  boolean can_explode_smashed;         // element explodes when smashed
+  boolean can_explode_impact;          // element explodes on impact
 
-  boolean modified_settings;   // set for all modified custom elements
+  boolean modified_settings;           // set for all modified custom elements
 };
 
 struct FontInfo
 {
-  char *token_name;            // font token used in config files
+  char *token_name;                    // font token used in config files
 
-  int graphic;                 // default graphic for this font
+  int graphic;                         // default graphic for this font
   int special_graphic[NUM_SPECIAL_GFX_ARGS];
-                               // special graphics for certain screens
+                                       // special graphics for certain screens
   int special_bitmap_id[NUM_SPECIAL_GFX_ARGS];
-                               // internal bitmap ID for special graphics
+                                       // internal bitmap ID for special graphics
 };
 
 struct GlobalAnimNameInfo
 {
-  char *token_name;            // global animation token in config files
+  char *token_name;                    // global animation token in config files
 };
 
 struct GlobalAnimInfo
 {
-  char *token_name;            // global animation token in config files
+  char *token_name;                    // global animation token in config files
 
   // global animation graphic and control definitions
   int graphic[NUM_GLOBAL_ANIM_PARTS_ALL][NUM_SPECIAL_GFX_ARGS];
@@ -3538,86 +4148,93 @@ struct GlobalAnimEventInfo
 
 struct GraphicInfo
 {
-  Bitmap **bitmaps;            // bitmaps in all required sizes
-  Bitmap *bitmap;              // bitmap in default size
+  Bitmap **bitmaps;                    // bitmaps in all required sizes
+  Bitmap *bitmap;                      // bitmap in default size
 
-  int src_image_width;         // scaled bitmap size, but w/o small images
-  int src_image_height;                // scaled bitmap size, but w/o small images
+  int src_image_width;                 // scaled bitmap size, but w/o small images
+  int src_image_height;                        // scaled bitmap size, but w/o small images
 
-  int src_x, src_y;            // start position of animation frames
-  int width, height;           // width/height of each animation frame
+  int src_x, src_y;                    // start position of animation frames
+  int width, height;                   // width/height of each animation frame
 
-  int offset_x, offset_y;      // x/y offset to next animation frame
-  int offset2_x, offset2_y;    // x/y offset to second movement tile
+  int offset_x, offset_y;              // x/y offset to next animation frame
+  int offset2_x, offset2_y;            // x/y offset to second movement tile
 
-  boolean double_movement;     // animation has second movement tile
-  int swap_double_tiles;       // explicitely force or forbid tile swapping
+  boolean double_movement;             // animation has second movement tile
+  int swap_double_tiles;               // explicitely force or forbid tile swapping
 
   int anim_frames;
   int anim_frames_per_line;
   int anim_start_frame;
-  int anim_delay;              // important: delay of 1 means "no delay"!
+  int anim_delay;                      // important: delay of 1 means "no delay"!
   int anim_mode;
 
   boolean anim_global_sync;
-
-  int crumbled_like;           // element for cloning crumble graphics
-  int diggable_like;           // element for cloning digging graphics
-
-  int border_size;             // border size for "crumbled" graphics
-
-  int scale_up_factor;         // optional factor for scaling image up
-  int tile_size;               // optional explicitly defined tile size
-
-  int clone_from;              // graphic for cloning *all* settings
-
-  int init_delay_fixed;                // optional initial delay values for global
-  int init_delay_random;       // animations (pause interval before start)
-  int init_delay_action;       // optional action called on animation start
-  int anim_delay_fixed;                // optional delay values for bored/sleeping
-  int anim_delay_random;       // and global animations (animation length)
-  int anim_delay_action;       // optional action called on animation end
-  int post_delay_fixed;                // optional delay values after bored/global
-  int post_delay_random;       // animations (pause before next animation)
-  int post_delay_action;       // optional action called after post delay
-
-  int init_event;              // optional event triggering animation start
-  int init_event_action;       // optional action called on animation start
-  int anim_event;              // optional event triggering animation end
-  int anim_event_action;       // optional action called on animation end
-
-  int step_offset;             // optional step offset of toon animations
-  int step_xoffset;            // optional step offset of toon animations
-  int step_yoffset;            // optional step offset of toon animations
-  int step_delay;              // optional step delay of toon animations
-  int direction;               // optional move direction of toon animations
-  int position;                        // optional draw position of toon animations
-  int x;                       // optional draw position of toon animations
-  int y;                       // optional draw position of toon animations
-
-  int draw_xoffset;            // optional offset for drawing font chars
-  int draw_yoffset;            // optional offset for drawing font chars
-
-  int draw_masked;             // optional setting for drawing envelope gfx
-  int draw_order;              // optional draw order for global animations
-
-  int fade_mode;               // optional setting for drawing title screens
-  int fade_delay;              // optional setting for drawing title screens
-  int post_delay;              // optional setting for drawing title screens
-  int auto_delay;              // optional setting for drawing title screens
-  int auto_delay_unit;         // optional setting for drawing title screens
-  int align, valign;           // optional setting for drawing title screens
-  int sort_priority;           // optional setting for drawing title screens
+  boolean anim_global_anim_sync;
+
+  int crumbled_like;                   // element for cloning crumble graphics
+  int diggable_like;                   // element for cloning digging graphics
+
+  int border_size;                     // border size for "crumbled" graphics
+
+  int scale_up_factor;                 // optional factor for scaling image up
+  int tile_size;                       // optional explicitly defined tile size
+
+  int clone_from;                      // graphic for cloning *all* settings
+
+  int init_delay_fixed;                        // optional initial delay values for global
+  int init_delay_random;               // animations (pause interval before start)
+  int init_delay_action;               // optional action called on animation start
+  int anim_delay_fixed;                        // optional delay values for bored/sleeping
+  int anim_delay_random;               // and global animations (animation length)
+  int anim_delay_action;               // optional action called on animation end
+  int post_delay_fixed;                        // optional delay values after bored/global
+  int post_delay_random;               // animations (pause before next animation)
+  int post_delay_action;               // optional action called after post delay
+
+  int init_event;                      // optional event triggering animation start
+  int init_event_action;               // optional action called on animation start
+  int anim_event;                      // optional event triggering animation end
+  int anim_event_action;               // optional action called on animation end
+
+  int step_offset;                     // optional step offset of toon animations
+  int step_xoffset;                    // optional step offset of toon animations
+  int step_yoffset;                    // optional step offset of toon animations
+  int step_delay;                      // optional step delay of toon animations
+  int direction;                       // optional move direction of toon animations
+  int position;                                // optional draw position of toon animations
+  int x;                               // optional draw position of toon animations
+  int y;                               // optional draw position of toon animations
+
+  int draw_xoffset;                    // optional offset for drawing font chars
+  int draw_yoffset;                    // optional offset for drawing font chars
+
+  int draw_masked;                     // optional setting for drawing envelope gfx
+  int draw_order;                      // optional draw order for global animations
+
+  int fade_mode;                       // optional setting for drawing title screens
+  int fade_delay;                      // optional setting for drawing title screens
+  int post_delay;                      // optional setting for drawing title screens
+  int auto_delay;                      // optional setting for drawing title screens
+  int auto_delay_unit;                 // optional setting for drawing title screens
+  int align, valign;                   // optional setting for drawing title screens
+  int sort_priority;                   // optional setting for drawing title screens
 
   int class;
   int style;
+  int alpha;
 
   int active_xoffset;
   int active_yoffset;
   int pressed_xoffset;
   int pressed_yoffset;
 
-  boolean use_image_size;      // use image size as default width and height
+  int stacked_xfactor;
+  int stacked_yfactor;
+  int stacked_xoffset;
+  int stacked_yoffset;
+
+  boolean use_image_size;              // use image size as default width and height
 };
 
 struct SoundInfo
@@ -3646,17 +4263,19 @@ struct MusicFileInfo
   char *artist_header;
   char *album_header;
   char *year_header;
+  char *played_header;
 
   char *title;
   char *artist;
   char *album;
   char *year;
+  char *played;
 
   int music;
 
   boolean is_sound;
 
-  struct MusicFileInfo *next;
+  struct MusicFileInfo *prev, *next;
 };
 
 struct ElementActionInfo
@@ -3688,165 +4307,171 @@ struct HelpAnimInfo
 };
 
 
-extern Bitmap                 *bitmap_db_field;
-extern Bitmap                 *bitmap_db_panel;
-extern Bitmap                 *bitmap_db_door_1;
-extern Bitmap                 *bitmap_db_door_2;
-extern Bitmap                 *bitmap_db_store_1;
-extern Bitmap                 *bitmap_db_store_2;
-extern DrawBuffer             *fieldbuffer;
-extern DrawBuffer             *drawto_field;
-
-extern int                     game_status;
-extern int                     game_status_last_screen;
-extern boolean                 level_editor_test_game;
-extern boolean                 network_playing;
-
-extern int                     key_joystick_mapping;
-
-extern short                   Tile[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   Last[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern boolean                 Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern boolean                 Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   AmoebaCnt[MAX_NUM_AMOEBA];
-extern short                   AmoebaCnt2[MAX_NUM_AMOEBA];
-extern short                   ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-
-extern int                     GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern int                     GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-
-extern int                     ActiveElement[MAX_NUM_ELEMENTS];
-extern int                     ActiveButton[NUM_IMAGE_FILES];
-extern int                     ActiveFont[NUM_FONTS];
-
-extern int                     lev_fieldx, lev_fieldy;
-extern int                     scroll_x, scroll_y;
-
-extern int                     WIN_XSIZE, WIN_YSIZE;
-extern int                     SCR_FIELDX, SCR_FIELDY;
-extern int                     REAL_SX, REAL_SY;
-extern int                     SX, SY;
-extern int                     DX, DY;
-extern int                     VX, VY;
-extern int                     EX, EY;
-extern int                     dDX, dDY;
-extern int                     FULL_SXSIZE, FULL_SYSIZE;
-extern int                     SXSIZE, SYSIZE;
-extern int                     DXSIZE, DYSIZE;
-extern int                     VXSIZE, VYSIZE;
-extern int                     EXSIZE, EYSIZE;
-extern int                     TILESIZE_VAR;
-
-extern int                     FADE_SX, FADE_SY;
-extern int                     FADE_SXSIZE, FADE_SYSIZE;
-
-extern int                     FX, FY;
-extern int                     ScrollStepSize;
-extern int                     ScreenMovDir, ScreenMovPos, ScreenGfxPos;
-extern int                     BorderElement;
-extern int                     MenuFrameDelay;
-extern int                     GameFrameDelay;
-extern int                     FfwdFrameDelay;
-extern int                     BX1, BY1;
-extern int                     BX2, BY2;
-extern int                     SBX_Left, SBX_Right;
-extern int                     SBY_Upper, SBY_Lower;
-
-extern int                     TimeFrames, TimePlayed, TimeLeft, TapeTime;
-
-extern boolean                 network_player_action_received;
-
-extern int                     graphics_action_mapping[];
-
-extern struct LevelInfo                level, level_template;
-extern struct ScoreInfo                scores, server_scores;
-extern struct TapeInfo         tape;
-extern struct GlobalInfo       global;
-extern struct BorderInfo       border;
-extern struct ViewportInfo     viewport;
-extern struct TitleFadingInfo  fading;
-extern struct TitleFadingInfo  fading_none;
-extern struct TitleFadingInfo  title_initial_first_default;
-extern struct TitleFadingInfo  title_initial_default;
-extern struct TitleFadingInfo  title_first_default;
-extern struct TitleFadingInfo  title_default;
-extern struct TitleMessageInfo titlescreen_initial_first_default;
-extern struct TitleMessageInfo titlescreen_initial_first[];
-extern struct TitleMessageInfo titlescreen_initial_default;
-extern struct TitleMessageInfo titlescreen_initial[];
-extern struct TitleMessageInfo titlescreen_first_default;
-extern struct TitleMessageInfo titlescreen_first[];
-extern struct TitleMessageInfo titlescreen_default;
-extern struct TitleMessageInfo titlescreen[];
-extern struct TitleMessageInfo titlemessage_initial_first_default;
-extern struct TitleMessageInfo titlemessage_initial_first[];
-extern struct TitleMessageInfo titlemessage_initial_default;
-extern struct TitleMessageInfo titlemessage_initial[];
-extern struct TitleMessageInfo titlemessage_first_default;
-extern struct TitleMessageInfo titlemessage_first[];
-extern struct TitleMessageInfo titlemessage_default;
-extern struct TitleMessageInfo titlemessage[];
-extern struct TitleMessageInfo readme;
-extern struct InitInfo         init, init_last;
-extern struct MenuInfo         menu;
-extern struct DoorInfo         door_1, door_2;
-extern struct RequestInfo      request;
-extern struct PreviewInfo      preview;
-extern struct EditorInfo       editor;
-extern struct ElementInfo      element_info[];
-extern struct ElementNameInfo  element_name_info[];
-extern struct ElementActionInfo        element_action_info[];
-extern struct ElementDirectionInfo element_direction_info[];
-extern struct SpecialSuffixInfo special_suffix_info[];
-extern struct TokenIntPtrInfo  image_config_vars[];
-extern struct FontInfo         font_info[];
-extern struct GlobalAnimInfo   global_anim_info[];
-extern struct GlobalAnimNameInfo global_anim_name_info[];
-extern struct GlobalAnimEventInfo global_anim_event_info;
-extern struct MusicPrefixInfo  music_prefix_info[];
-extern struct GraphicInfo      *graphic_info;
-extern struct SoundInfo               *sound_info;
-extern struct MusicInfo               *music_info;
-extern struct MusicFileInfo    *music_file_info;
-extern struct HelpAnimInfo     *helpanim_info;
-extern SetupFileHash           *helptext_info;
-extern SetupFileHash          *image_config_hash;
-extern SetupFileHash          *element_token_hash;
-extern SetupFileHash          *graphic_token_hash;
-extern SetupFileHash          *font_token_hash;
-extern SetupFileHash          *hide_setup_hash;
-extern struct ConfigTypeInfo   image_config_suffix[];
-extern struct ConfigTypeInfo   sound_config_suffix[];
-extern struct ConfigTypeInfo   music_config_suffix[];
-extern struct ConfigInfo       image_config[];
-extern struct ConfigInfo       sound_config[];
-extern struct ConfigInfo       music_config[];
-extern struct ConfigInfo       helpanim_config[];
-extern struct ConfigInfo       helptext_config[];
+extern Bitmap                         *bitmap_db_field;
+extern Bitmap                         *bitmap_db_door_1;
+extern Bitmap                         *bitmap_db_door_2;
+extern Bitmap                         *bitmap_db_store_1;
+extern Bitmap                         *bitmap_db_store_2;
+extern DrawBuffer                     *fieldbuffer;
+extern DrawBuffer                     *drawto_field;
+
+extern int                             game_status;
+extern int                             game_status_last_screen;
+extern boolean                         level_editor_test_game;
+extern boolean                         score_info_tape_play;
+extern boolean                         network_playing;
+
+extern int                             key_joystick_mapping;
+
+extern short                           Tile[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           Last[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern boolean                         Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern boolean                         Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           CheckImpact[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           AmoebaCnt[MAX_NUM_AMOEBA];
+extern short                           AmoebaCnt2[MAX_NUM_AMOEBA];
+extern short                           ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                           ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+extern int                             GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxRandomStatic[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxElementEmpty[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                             GfxRedraw[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+extern int                             ActiveElement[MAX_NUM_ELEMENTS];
+extern int                             ActiveButton[NUM_IMAGE_FILES];
+extern int                             ActiveFont[NUM_FONTS];
+
+extern int                             lev_fieldx, lev_fieldy;
+extern int                             scroll_x, scroll_y;
+
+extern int                             WIN_XSIZE, WIN_YSIZE;
+extern int                             SCR_FIELDX, SCR_FIELDY;
+extern int                             REAL_SX, REAL_SY;
+extern int                             SX, SY;
+extern int                             DX, DY;
+extern int                             VX, VY;
+extern int                             EX, EY;
+extern int                             dDX, dDY;
+extern int                             FULL_SXSIZE, FULL_SYSIZE;
+extern int                             SXSIZE, SYSIZE;
+extern int                             DXSIZE, DYSIZE;
+extern int                             VXSIZE, VYSIZE;
+extern int                             EXSIZE, EYSIZE;
+extern int                             TILESIZE_VAR;
+
+extern int                             FADE_SX, FADE_SY;
+extern int                             FADE_SXSIZE, FADE_SYSIZE;
+
+extern int                             FX, FY;
+extern int                             ScrollStepSize;
+extern int                             ScreenMovDir, ScreenMovPos, ScreenGfxPos;
+extern int                             BorderElement;
+extern int                             MenuFrameDelay;
+extern int                             GameFrameDelay;
+extern int                             FfwdFrameDelay;
+extern int                             BX1, BY1;
+extern int                             BX2, BY2;
+extern int                             SBX_Left, SBX_Right;
+extern int                             SBY_Upper, SBY_Lower;
+
+extern int                             TimeFrames, TimePlayed, TimeLeft;
+extern int                             TapeTimeFrames, TapeTime;
+
+extern boolean                         network_player_action_received;
+
+extern int                             graphics_action_mapping[];
+
+extern struct LevelInfo                        level, level_template;
+extern struct ScoreInfo                        scores, server_scores;
+extern struct TapeInfo                 tape;
+extern struct GlobalInfo               global;
+extern struct BorderInfo               border;
+extern struct ViewportInfo             viewport;
+extern struct TitleFadingInfo          fading;
+extern struct TitleFadingInfo          fading_none;
+extern struct TitleFadingInfo          title_initial_first_default;
+extern struct TitleFadingInfo          title_initial_default;
+extern struct TitleFadingInfo          title_first_default;
+extern struct TitleFadingInfo          title_default;
+extern struct TitleMessageInfo         titlescreen_initial_first_default;
+extern struct TitleMessageInfo         titlescreen_initial_first[];
+extern struct TitleMessageInfo         titlescreen_initial_default;
+extern struct TitleMessageInfo         titlescreen_initial[];
+extern struct TitleMessageInfo         titlescreen_first_default;
+extern struct TitleMessageInfo         titlescreen_first[];
+extern struct TitleMessageInfo         titlescreen_default;
+extern struct TitleMessageInfo         titlescreen[];
+extern struct TitleMessageInfo         titlemessage_initial_first_default;
+extern struct TitleMessageInfo         titlemessage_initial_first[];
+extern struct TitleMessageInfo         titlemessage_initial_default;
+extern struct TitleMessageInfo         titlemessage_initial[];
+extern struct TitleMessageInfo         titlemessage_first_default;
+extern struct TitleMessageInfo         titlemessage_first[];
+extern struct TitleMessageInfo         titlemessage_default;
+extern struct TitleMessageInfo         titlemessage[];
+extern struct TitleMessageInfo         readme;
+extern struct InitInfo                 init, init_last;
+extern struct MenuInfo                 menu;
+extern struct DoorInfo                 door_1, door_2;
+extern struct RequestInfo              request;
+extern struct PreviewInfo              preview;
+extern struct EditorInfo               editor;
+extern struct ElementInfo              element_info[];
+extern struct ElementNameInfo          element_name_info[];
+extern struct ElementActionInfo                element_action_info[];
+extern struct ElementDirectionInfo     element_direction_info[];
+extern struct SpecialSuffixInfo                special_suffix_info[];
+extern struct TokenIntPtrInfo          image_config_vars[];
+extern struct TokenIntPtrInfo          sound_config_vars[];
+extern struct FontInfo                 font_info[];
+extern struct GlobalAnimInfo           global_anim_info[];
+extern struct GlobalAnimNameInfo       global_anim_name_info[];
+extern struct GlobalAnimEventInfo      global_anim_event_info;
+extern struct MusicPrefixInfo          music_prefix_info[];
+extern struct GraphicInfo             *graphic_info;
+extern struct SoundInfo                       *sound_info;
+extern struct MusicInfo                       *music_info;
+extern struct MusicFileInfo           *music_file_info;
+extern struct HelpAnimInfo            *helpanim_info;
+extern SetupFileHash                  *helptext_info;
+extern SetupFileHash                  *image_config_hash;
+extern SetupFileHash                  *sound_config_hash;
+extern SetupFileHash                  *element_token_hash;
+extern SetupFileHash                  *graphic_token_hash;
+extern SetupFileHash                  *font_token_hash;
+extern SetupFileHash                  *hide_setup_hash;
+extern SetupFileHash                  *anim_url_hash;
+extern struct ConfigTypeInfo           image_config_suffix[];
+extern struct ConfigTypeInfo           sound_config_suffix[];
+extern struct ConfigTypeInfo           music_config_suffix[];
+extern struct ConfigInfo               image_config[];
+extern struct ConfigInfo               sound_config[];
+extern struct ConfigInfo               music_config[];
+extern struct ConfigInfo               helpanim_config[];
+extern struct ConfigInfo               helptext_config[];
 
 #endif // MAIN_H
index 9fd230c21772e7780729574d960a45e23992dc07..67bab2284dd4da847b7305532ada28e39b6dad99 100644 (file)
 
 #include "main.h"
 
-#define DEFAULT_SERVER_PORT    19504
-
-#define PROTOCOL_VERSION_MAJOR 2
-#define PROTOCOL_VERSION_MINOR 0
-#define PROTOCOL_VERSION_PATCH 0
-
-#define OP_PROTOCOL_VERSION    1
-#define OP_BAD_PROTOCOL_VERSION        2
-#define OP_YOUR_NUMBER         3
-#define OP_NUMBER_WANTED       4
-#define OP_PLAYER_NAME         5
-#define OP_PLAYER_CONNECTED    6
-#define OP_PLAYER_DISCONNECTED 7
-#define OP_START_PLAYING       8
-#define OP_PAUSE_PLAYING       9
-#define OP_CONTINUE_PLAYING    10
-#define OP_STOP_PLAYING                11
-#define OP_MOVE_PLAYER         12
-#define OP_BROADCAST_MESSAGE   13
-#define OP_LEVEL_FILE          14
-
-#define MAX_BUFFER_SIZE                4096
-#define MAX_PACKET_SIZE                1048576
+#define DEFAULT_SERVER_PORT            19504
+
+#define PROTOCOL_VERSION_MAJOR         2
+#define PROTOCOL_VERSION_MINOR         0
+#define PROTOCOL_VERSION_PATCH         0
+
+#define OP_PROTOCOL_VERSION            1
+#define OP_BAD_PROTOCOL_VERSION                2
+#define OP_YOUR_NUMBER                 3
+#define OP_NUMBER_WANTED               4
+#define OP_PLAYER_NAME                 5
+#define OP_PLAYER_CONNECTED            6
+#define OP_PLAYER_DISCONNECTED         7
+#define OP_START_PLAYING               8
+#define OP_PAUSE_PLAYING               9
+#define OP_CONTINUE_PLAYING            10
+#define OP_STOP_PLAYING                        11
+#define OP_MOVE_PLAYER                 12
+#define OP_BROADCAST_MESSAGE           13
+#define OP_LEVEL_FILE                  14
+
+#define MAX_BUFFER_SIZE                        4096
+#define MAX_PACKET_SIZE                        1048576
 
 
 struct NetworkBuffer
index e72e578601bc889dbc2c1e538feb11f1d6b60ee8..a31e6121f4dd28b255bf69843a11cff503a0ce54 100644 (file)
 #include "network.h"
 #include "init.h"
 #include "config.h"
+#include "api.h"
 
 
-#define DEBUG_JOYSTICKS                0
+#define DEBUG_JOYSTICKS                                0
 
 
 // screens on the info screen
-#define INFO_MODE_MAIN                 0
-#define INFO_MODE_TITLE                        1
-#define INFO_MODE_ELEMENTS             2
-#define INFO_MODE_MUSIC                        3
-#define INFO_MODE_CREDITS              4
-#define INFO_MODE_PROGRAM              5
-#define INFO_MODE_VERSION              6
-#define INFO_MODE_LEVELSET             7
+#define INFO_MODE_MAIN                         0
+#define INFO_MODE_TITLE                                1
+#define INFO_MODE_ELEMENTS                     2
+#define INFO_MODE_MUSIC                                3
+#define INFO_MODE_CREDITS                      4
+#define INFO_MODE_PROGRAM                      5
+#define INFO_MODE_VERSION                      6
+#define INFO_MODE_LEVELSET                     7
 
-#define MAX_INFO_MODES                 8
+#define MAX_INFO_MODES                         8
 
 // screens on the setup screen
 // (must match GFX_SPECIAL_ARG_SETUP_* values as defined in src/main.h)
 // (should also match corresponding entries in src/conf_gfx.c)
-#define SETUP_MODE_MAIN                        0
-#define SETUP_MODE_GAME                        1
-#define SETUP_MODE_ENGINES             2
-#define SETUP_MODE_EDITOR              3
-#define SETUP_MODE_GRAPHICS            4
-#define SETUP_MODE_SOUND               5
-#define SETUP_MODE_ARTWORK             6
-#define SETUP_MODE_INPUT               7
-#define SETUP_MODE_TOUCH               8
-#define SETUP_MODE_SHORTCUTS           9
-#define SETUP_MODE_SHORTCUTS_1         10
-#define SETUP_MODE_SHORTCUTS_2         11
-#define SETUP_MODE_SHORTCUTS_3         12
-#define SETUP_MODE_SHORTCUTS_4         13
-#define SETUP_MODE_SHORTCUTS_5         14
+#define SETUP_MODE_MAIN                                0
+#define SETUP_MODE_GAME                                1
+#define SETUP_MODE_ENGINES                     2
+#define SETUP_MODE_EDITOR                      3
+#define SETUP_MODE_GRAPHICS                    4
+#define SETUP_MODE_SOUND                       5
+#define SETUP_MODE_ARTWORK                     6
+#define SETUP_MODE_INPUT                       7
+#define SETUP_MODE_TOUCH                       8
+#define SETUP_MODE_SHORTCUTS                   9
+#define SETUP_MODE_SHORTCUTS_1                 10
+#define SETUP_MODE_SHORTCUTS_2                 11
+#define SETUP_MODE_SHORTCUTS_3                 12
+#define SETUP_MODE_SHORTCUTS_4                 13
+#define SETUP_MODE_SHORTCUTS_5                 14
+#define SETUP_MODE_SHORTCUTS_6                 15
 
 // sub-screens on the setup screen (generic)
-#define SETUP_MODE_CHOOSE_ARTWORK      15
-#define SETUP_MODE_CHOOSE_OTHER                16
+#define SETUP_MODE_CHOOSE_ARTWORK              16
+#define SETUP_MODE_CHOOSE_OTHER                        17
 
 // sub-screens on the setup screen (specific)
-#define SETUP_MODE_CHOOSE_SCORES_TYPE  17
-#define SETUP_MODE_CHOOSE_GAME_SPEED   18
-#define SETUP_MODE_CHOOSE_SCROLL_DELAY 19
-#define SETUP_MODE_CHOOSE_SNAPSHOT_MODE        20
-#define SETUP_MODE_CHOOSE_WINDOW_SIZE  21
-#define SETUP_MODE_CHOOSE_SCALING_TYPE 22
-#define SETUP_MODE_CHOOSE_RENDERING    23
-#define SETUP_MODE_CHOOSE_VSYNC                24
-#define SETUP_MODE_CHOOSE_GRAPHICS     25
-#define SETUP_MODE_CHOOSE_SOUNDS       26
-#define SETUP_MODE_CHOOSE_MUSIC                27
-#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE        28
-#define SETUP_MODE_CHOOSE_VOLUME_LOOPS 29
-#define SETUP_MODE_CHOOSE_VOLUME_MUSIC 30
-#define SETUP_MODE_CHOOSE_TOUCH_CONTROL        31
-#define SETUP_MODE_CHOOSE_MOVE_DISTANCE        32
-#define SETUP_MODE_CHOOSE_DROP_DISTANCE        33
-#define SETUP_MODE_CHOOSE_TRANSPARENCY 34
-#define SETUP_MODE_CHOOSE_GRID_XSIZE_0 35
-#define SETUP_MODE_CHOOSE_GRID_YSIZE_0 36
-#define SETUP_MODE_CHOOSE_GRID_XSIZE_1 37
-#define SETUP_MODE_CHOOSE_GRID_YSIZE_1 38
-#define SETUP_MODE_CONFIG_VIRT_BUTTONS 39
-
-#define MAX_SETUP_MODES                        40
-
-#define MAX_MENU_MODES                 MAX(MAX_INFO_MODES, MAX_SETUP_MODES)
+#define SETUP_MODE_CHOOSE_SCORES_TYPE          18
+#define SETUP_MODE_CHOOSE_GAME_SPEED           19
+#define SETUP_MODE_CHOOSE_SCROLL_DELAY         20
+#define SETUP_MODE_CHOOSE_SNAPSHOT_MODE                21
+#define SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE     22
+#define SETUP_MODE_CHOOSE_BD_PALETTE_C64       23
+#define SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV    24
+#define SETUP_MODE_CHOOSE_BD_PALETTE_ATARI     25
+#define SETUP_MODE_CHOOSE_BD_COLOR_TYPE                26
+#define SETUP_MODE_CHOOSE_WINDOW_SIZE          27
+#define SETUP_MODE_CHOOSE_SCALING_TYPE         28
+#define SETUP_MODE_CHOOSE_RENDERING            29
+#define SETUP_MODE_CHOOSE_VSYNC                        30
+#define SETUP_MODE_CHOOSE_GRAPHICS             31
+#define SETUP_MODE_CHOOSE_SOUNDS               32
+#define SETUP_MODE_CHOOSE_MUSIC                        33
+#define SETUP_MODE_CHOOSE_VOLUME_SIMPLE                34
+#define SETUP_MODE_CHOOSE_VOLUME_LOOPS         35
+#define SETUP_MODE_CHOOSE_VOLUME_MUSIC         36
+#define SETUP_MODE_CHOOSE_TOUCH_CONTROL                37
+#define SETUP_MODE_CHOOSE_MOVE_DISTANCE                38
+#define SETUP_MODE_CHOOSE_DROP_DISTANCE                39
+#define SETUP_MODE_CHOOSE_TRANSPARENCY         40
+#define SETUP_MODE_CHOOSE_GRID_XSIZE_0         41
+#define SETUP_MODE_CHOOSE_GRID_YSIZE_0         42
+#define SETUP_MODE_CHOOSE_GRID_XSIZE_1         43
+#define SETUP_MODE_CHOOSE_GRID_YSIZE_1         44
+#define SETUP_MODE_CONFIG_VIRT_BUTTONS         45
+
+#define MAX_SETUP_MODES                                46
+
+#define MAX_MENU_MODES                         MAX(MAX_INFO_MODES, MAX_SETUP_MODES)
+
+// info screen titles
+#define STR_INFO_MAIN                          "Info Screen"
+#define STR_INFO_TITLE                         "Title Screen"
+#define STR_INFO_ELEMENTS                      "Game Elements"
+#define STR_INFO_MUSIC                         "Music Info"
+#define STR_INFO_CREDITS                       "Credits"
+#define STR_INFO_PROGRAM                       "Program Info"
+#define STR_INFO_VERSION                       "Version Info"
+#define STR_INFO_LEVELSET                      "Level Set Info"
+#define STR_INFO_EXIT                          "Exit"
 
 // setup screen titles
-#define STR_SETUP_MAIN                 "Setup"
-#define STR_SETUP_GAME                 "Game & Menu"
-#define STR_SETUP_ENGINES              "Game Engines"
-#define STR_SETUP_EDITOR               "Editor"
-#define STR_SETUP_GRAPHICS             "Graphics"
-#define STR_SETUP_SOUND                        "Sound & Music"
-#define STR_SETUP_ARTWORK              "Custom Artwork"
-#define STR_SETUP_INPUT                        "Input Devices"
-#define STR_SETUP_TOUCH                        "Touch Controls"
-#define STR_SETUP_SHORTCUTS            "Key Shortcuts"
-#define STR_SETUP_EXIT                 "Exit"
-#define STR_SETUP_SAVE_AND_EXIT                "Save and Exit"
-
-#define STR_SETUP_CHOOSE_SCORES_TYPE   "Scores Type"
-#define STR_SETUP_CHOOSE_GAME_SPEED    "Game Speed"
-#define STR_SETUP_CHOOSE_SCROLL_DELAY  "Scroll Delay"
-#define STR_SETUP_CHOOSE_SNAPSHOT_MODE "Snapshot Mode"
-#define STR_SETUP_CHOOSE_WINDOW_SIZE   "Window Scaling"
-#define STR_SETUP_CHOOSE_SCALING_TYPE  "Anti-Aliasing"
-#define STR_SETUP_CHOOSE_RENDERING     "Rendering Mode"
-#define STR_SETUP_CHOOSE_VSYNC         "VSync Mode"
-#define STR_SETUP_CHOOSE_VOLUME_SIMPLE "Sound Volume"
-#define STR_SETUP_CHOOSE_VOLUME_LOOPS  "Loops Volume"
-#define STR_SETUP_CHOOSE_VOLUME_MUSIC  "Music Volume"
-#define STR_SETUP_CHOOSE_TOUCH_CONTROL "Control Type"
-#define STR_SETUP_CHOOSE_MOVE_DISTANCE "Move Distance"
-#define STR_SETUP_CHOOSE_DROP_DISTANCE "Drop Distance"
-#define STR_SETUP_CHOOSE_TRANSPARENCY  "Transparency"
-#define STR_SETUP_CHOOSE_GRID_XSIZE_0  "Horiz. Buttons"
-#define STR_SETUP_CHOOSE_GRID_YSIZE_0  "Vert. Buttons"
-#define STR_SETUP_CHOOSE_GRID_XSIZE_1  "Horiz. Buttons"
-#define STR_SETUP_CHOOSE_GRID_YSIZE_1  "Vert. Buttons"
+#define STR_SETUP_MAIN                         "Setup"
+#define STR_SETUP_GAME                         "Game & Menu"
+#define STR_SETUP_ENGINES                      "Game Engines"
+#define STR_SETUP_EDITOR                       "Editor"
+#define STR_SETUP_GRAPHICS                     "Graphics"
+#define STR_SETUP_SOUND                                "Sound & Music"
+#define STR_SETUP_ARTWORK                      "Custom Artwork"
+#define STR_SETUP_INPUT                                "Input Devices"
+#define STR_SETUP_TOUCH                                "Touch Controls"
+#define STR_SETUP_SHORTCUTS                    "Key Shortcuts"
+#define STR_SETUP_EXIT                         "Exit"
+#define STR_SETUP_SAVE_AND_EXIT                        "Save and Exit"
+
+#define STR_SETUP_CHOOSE_SCORES_TYPE           "Scores Type"
+#define STR_SETUP_CHOOSE_GAME_SPEED            "Game Speed"
+#define STR_SETUP_CHOOSE_SCROLL_DELAY          "Scroll Delay"
+#define STR_SETUP_CHOOSE_SNAPSHOT_MODE         "Snapshot Mode"
+#define STR_SETUP_CHOOSE_GAME_ENGINE_TYPE      "Game Engine"
+#define STR_SETUP_CHOOSE_BD_PALETTE_C64                "Palette (C64)"
+#define STR_SETUP_CHOOSE_BD_PALETTE_C64DTV     "Palette (C64DTV)"
+#define STR_SETUP_CHOOSE_BD_PALETTE_ATARI      "Palette (Atari)"
+#define STR_SETUP_CHOOSE_BD_COLOR_TYPE         "Color Type"
+#define STR_SETUP_CHOOSE_WINDOW_SIZE           "Window Scaling"
+#define STR_SETUP_CHOOSE_SCALING_TYPE          "Anti-Aliasing"
+#define STR_SETUP_CHOOSE_RENDERING             "Rendering Mode"
+#define STR_SETUP_CHOOSE_VSYNC                 "VSync Mode"
+#define STR_SETUP_CHOOSE_VOLUME_SIMPLE         "Sound Volume"
+#define STR_SETUP_CHOOSE_VOLUME_LOOPS          "Loops Volume"
+#define STR_SETUP_CHOOSE_VOLUME_MUSIC          "Music Volume"
+#define STR_SETUP_CHOOSE_TOUCH_CONTROL         "Control Type"
+#define STR_SETUP_CHOOSE_MOVE_DISTANCE         "Move Distance"
+#define STR_SETUP_CHOOSE_DROP_DISTANCE         "Drop Distance"
+#define STR_SETUP_CHOOSE_TRANSPARENCY          "Transparency"
+#define STR_SETUP_CHOOSE_GRID_XSIZE_0          "Horiz. Buttons"
+#define STR_SETUP_CHOOSE_GRID_YSIZE_0          "Vert. Buttons"
+#define STR_SETUP_CHOOSE_GRID_XSIZE_1          "Horiz. Buttons"
+#define STR_SETUP_CHOOSE_GRID_YSIZE_1          "Vert. Buttons"
 
 // other screen text constants
-#define STR_CHOOSE_TREE_EDIT           "Edit"
-#define MENU_CHOOSE_TREE_FONT(x)       (FONT_TEXT_1 + (x))
-#define MENU_CHOOSE_TREE_COLOR(ti, a)  TREE_COLOR(ti, a)
+#define STR_CHOOSE_TREE_EDIT                   "Edit"
+#define MENU_CHOOSE_TREE_FONT(x)               (FONT_TEXT_1 + (x))
+#define MENU_CHOOSE_TREE_COLOR(ti, a)          TREE_COLOR(ti, a)
+
+#define TEXT_MAIN_MENU                         "Press any key or button for main menu"
+#define TEXT_INFO_MENU                         "Press any key or button for info menu"
+#define TEXT_NEXT_PAGE                         "Press any key or button for next page"
+#define TEXT_NEXT_MENU                         (info_screens_from_main ?               \
+                                                TEXT_MAIN_MENU : TEXT_INFO_MENU)
 
 // for input setup functions
-#define SETUPINPUT_SCREEN_POS_START    0
-#define SETUPINPUT_SCREEN_POS_EMPTY1   3
-#define SETUPINPUT_SCREEN_POS_EMPTY2   12
-#define SETUPINPUT_SCREEN_POS_END      13
+#define SETUPINPUT_SCREEN_POS_START            0
+#define SETUPINPUT_SCREEN_POS_EMPTY1           3
+#define SETUPINPUT_SCREEN_POS_EMPTY2           12
+#define SETUPINPUT_SCREEN_POS_END              13
 
-#define MENU_SETUP_FONT_TITLE          FONT_TEXT_1
-#define MENU_SETUP_FONT_TEXT           FONT_TITLE_2
+#define MENU_SETUP_FONT_TITLE                  FONT_TEXT_1
+#define MENU_SETUP_FONT_TEXT                   FONT_TITLE_2
 
-#define MAX_SETUP_TEXT_INPUT_LEN       28
+#define MAX_SETUP_TEXT_INPUT_LEN               28
 
 // for various menu stuff
-#define MENU_SCREEN_START_XPOS         1
-#define MENU_SCREEN_START_YPOS         2
-#define MENU_SCREEN_VALUE_XPOS         (SCR_FIELDX - 3)
-#define MENU_SCREEN_TEXT2_XPOS         (SCR_FIELDX - 2)
-#define MENU_SCREEN_MAX_XPOS           (SCR_FIELDX - 1)
-#define MENU_TITLE1_YPOS               8
-#define MENU_TITLE2_YPOS               46
-#define MENU_INFO_FONT_TITLE           FONT_TEXT_1
-#define MENU_INFO_FONT_HEAD            FONT_TEXT_2
-#define MENU_INFO_FONT_TEXT            FONT_TEXT_3
-#define MENU_INFO_FONT_FOOT            FONT_TEXT_4
-#define MENU_INFO_SPACE_HEAD           (menu.headline2_spacing_info[info_mode])
-#define MENU_SCREEN_INFO_SPACE_LEFT    (menu.left_spacing_info[info_mode])
-#define MENU_SCREEN_INFO_SPACE_RIGHT   (menu.right_spacing_info[info_mode])
-#define MENU_SCREEN_INFO_SPACE_TOP     (menu.top_spacing_info[info_mode])
-#define MENU_SCREEN_INFO_SPACE_BOTTOM  (menu.bottom_spacing_info[info_mode])
-#define MENU_SCREEN_INFO_YSTART1       MENU_SCREEN_INFO_SPACE_TOP
-#define MENU_SCREEN_INFO_YSTART2       (MENU_SCREEN_INFO_YSTART1 +            \
-                                        getMenuTextStep(MENU_INFO_SPACE_HEAD, \
-                                                        MENU_INFO_FONT_TITLE))
-#define MENU_SCREEN_INFO_YSTEP         (TILEY + 4)
-#define MENU_SCREEN_INFO_YBOTTOM       (SYSIZE - MENU_SCREEN_INFO_SPACE_BOTTOM)
-#define MENU_SCREEN_INFO_YSIZE         (MENU_SCREEN_INFO_YBOTTOM -     \
-                                        MENU_SCREEN_INFO_YSTART2 -     \
-                                        TILEY / 2)
-#define MAX_INFO_ELEMENTS_ON_SCREEN    128
-#define STD_INFO_ELEMENTS_ON_SCREEN    (MENU_SCREEN_INFO_YSIZE /       \
-                                        MENU_SCREEN_INFO_YSTEP)
-#define NUM_INFO_ELEMENTS_FROM_CONF    \
-  (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ?            \
-   menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] :                        \
-   MAX_MENU_ENTRIES_ON_SCREEN)
-#define NUM_INFO_ELEMENTS_ON_SCREEN    MIN(MIN(STD_INFO_ELEMENTS_ON_SCREEN, \
-                                                MAX_INFO_ELEMENTS_ON_SCREEN), \
-                                           NUM_INFO_ELEMENTS_FROM_CONF)
-#define MAX_MENU_ENTRIES_ON_SCREEN     (SCR_FIELDY - MENU_SCREEN_START_YPOS)
-#define MAX_MENU_TEXT_LENGTH_BIG       13
-#define MAX_MENU_TEXT_LENGTH_MEDIUM    (MAX_MENU_TEXT_LENGTH_BIG * 2)
+#define MENU_SCREEN_START_XPOS                 1
+#define MENU_SCREEN_START_YPOS                 2
+#define MENU_SCREEN_VALUE_XPOS                 (SCR_FIELDX - 3)
+#define MENU_SCREEN_TEXT2_XPOS                 (SCR_FIELDX - 2)
+#define MENU_SCREEN_MAX_XPOS                   (SCR_FIELDX - 1)
+#define MENU_TITLE1_YPOS                       8
+#define MENU_TITLE2_YPOS                       46
+#define MENU_INFO_FONT_TITLE                   FONT_TEXT_1
+#define MENU_INFO_FONT_HEAD                    FONT_TEXT_2
+#define MENU_INFO_FONT_TEXT                    FONT_TEXT_3
+#define MENU_INFO_FONT_FOOT                    FONT_TEXT_4
+#define MENU_INFO_SPACE_HEAD                   (menu.headline2_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_LEFT            (menu.left_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_MIDDLE          (menu.middle_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_RIGHT           (menu.right_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_TOP             (menu.top_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_BOTTOM          (menu.bottom_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_LINE            (menu.line_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_SPACE_EXTRA           (menu.extra_spacing_info[info_mode])
+#define MENU_SCREEN_INFO_TILE_SIZE_RAW         (menu.tile_size_info[info_mode])
+#define MENU_SCREEN_INFO_TILE_SIZE             (MENU_SCREEN_INFO_TILE_SIZE_RAW > 0 ?           \
+                                                MENU_SCREEN_INFO_TILE_SIZE_RAW : TILEY)
+#define MENU_SCREEN_INFO_ENTRY_SIZE_RAW                (menu.list_entry_size_info[info_mode])
+#define MENU_SCREEN_INFO_ENTRY_SIZE            (MAX(MENU_SCREEN_INFO_ENTRY_SIZE_RAW,           \
+                                                    MENU_SCREEN_INFO_TILE_SIZE))
+#define MENU_SCREEN_INFO_YSTART                        MENU_SCREEN_INFO_SPACE_TOP
+#define MENU_SCREEN_INFO_YSTEP                 (MENU_SCREEN_INFO_ENTRY_SIZE +                  \
+                                                MENU_SCREEN_INFO_SPACE_EXTRA)
+#define MENU_SCREEN_INFO_YBOTTOM               (SYSIZE - MENU_SCREEN_INFO_SPACE_BOTTOM)
+#define MENU_SCREEN_INFO_YSIZE                 (MENU_SCREEN_INFO_YBOTTOM -                     \
+                                                MENU_SCREEN_INFO_YSTART - TILEY / 2)
+#define MAX_INFO_ELEMENTS_IN_ARRAY             128
+#define MAX_INFO_ELEMENTS_ON_SCREEN            (SYSIZE / TILEY)
+#define MAX_INFO_ELEMENTS                      MIN(MAX_INFO_ELEMENTS_IN_ARRAY,                 \
+                                                   MAX_INFO_ELEMENTS_ON_SCREEN)
+#define STD_INFO_ELEMENTS_ON_SCREEN            10
+#define DYN_INFO_ELEMENTS_ON_SCREEN            (MENU_SCREEN_INFO_YSIZE / MENU_SCREEN_INFO_YSTEP)
+#define DEFAULT_INFO_ELEMENTS                  MIN(STD_INFO_ELEMENTS_ON_SCREEN,                \
+                                                   DYN_INFO_ELEMENTS_ON_SCREEN)
+#define NUM_INFO_ELEMENTS_FROM_CONF                                    \
+                               (menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] > 0 ?       \
+                                menu.list_size_info[GFX_SPECIAL_ARG_INFO_ELEMENTS] :           \
+                                DEFAULT_INFO_ELEMENTS)
+#define NUM_INFO_ELEMENTS_ON_SCREEN            MIN(NUM_INFO_ELEMENTS_FROM_CONF, MAX_INFO_ELEMENTS)
+#define MAX_MENU_ENTRIES_ON_SCREEN             (SCR_FIELDY - MENU_SCREEN_START_YPOS)
+#define MAX_MENU_TEXT_LENGTH_BIG               13
+#define MAX_MENU_TEXT_LENGTH_MEDIUM            (MAX_MENU_TEXT_LENGTH_BIG * 2)
 
 // screen gadget identifiers
-#define SCREEN_CTRL_ID_PREV_LEVEL      0
-#define SCREEN_CTRL_ID_NEXT_LEVEL      1
-#define SCREEN_CTRL_ID_FIRST_LEVEL     2
-#define SCREEN_CTRL_ID_LAST_LEVEL      3
-#define SCREEN_CTRL_ID_LEVEL_NUMBER    4
-#define SCREEN_CTRL_ID_PREV_PLAYER     5
-#define SCREEN_CTRL_ID_NEXT_PLAYER     6
-#define SCREEN_CTRL_ID_INSERT_SOLUTION 7
-#define SCREEN_CTRL_ID_PLAY_SOLUTION   8
-#define SCREEN_CTRL_ID_SWITCH_ECS_AGA  9
-#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE 10
-#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE 11
-#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE2        12
-#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE2        13
-#define SCREEN_CTRL_ID_SCROLL_UP       14
-#define SCREEN_CTRL_ID_SCROLL_DOWN     15
-#define SCREEN_CTRL_ID_SCROLL_VERTICAL 16
-#define SCREEN_CTRL_ID_NETWORK_SERVER  17
-
-#define NUM_SCREEN_GADGETS             18
-
-#define NUM_SCREEN_MENUBUTTONS         14
-#define NUM_SCREEN_SCROLLBUTTONS       2
-#define NUM_SCREEN_SCROLLBARS          1
-#define NUM_SCREEN_TEXTINPUT           1
-
-#define SCREEN_MASK_MAIN               (1 << 0)
-#define SCREEN_MASK_MAIN_HAS_SOLUTION  (1 << 1)
-#define SCREEN_MASK_INPUT              (1 << 2)
-#define SCREEN_MASK_TOUCH              (1 << 3)
-#define SCREEN_MASK_TOUCH2             (1 << 4)
+#define SCREEN_CTRL_ID_PREV_LEVEL              0
+#define SCREEN_CTRL_ID_NEXT_LEVEL              1
+#define SCREEN_CTRL_ID_PREV_LEVEL2             2
+#define SCREEN_CTRL_ID_NEXT_LEVEL2             3
+#define SCREEN_CTRL_ID_PREV_SCORE              4
+#define SCREEN_CTRL_ID_NEXT_SCORE              5
+#define SCREEN_CTRL_ID_PLAY_TAPE               6
+#define SCREEN_CTRL_ID_FIRST_LEVEL             7
+#define SCREEN_CTRL_ID_LAST_LEVEL              8
+#define SCREEN_CTRL_ID_LEVEL_NUMBER            9
+#define SCREEN_CTRL_ID_PREV_PLAYER             10
+#define SCREEN_CTRL_ID_NEXT_PLAYER             11
+#define SCREEN_CTRL_ID_INSERT_SOLUTION         12
+#define SCREEN_CTRL_ID_PLAY_SOLUTION           13
+#define SCREEN_CTRL_ID_LEVELSET_INFO           14
+#define SCREEN_CTRL_ID_SWITCH_ECS_AGA          15
+#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE         16
+#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE         17
+#define SCREEN_CTRL_ID_TOUCH_PREV_PAGE2                18
+#define SCREEN_CTRL_ID_TOUCH_NEXT_PAGE2                19
+
+#define NUM_SCREEN_MENUBUTTONS                 20
+
+#define SCREEN_CTRL_ID_SCROLL_UP               20
+#define SCREEN_CTRL_ID_SCROLL_DOWN             21
+#define SCREEN_CTRL_ID_SCROLL_VERTICAL         22
+#define SCREEN_CTRL_ID_NETWORK_SERVER          23
+
+#define NUM_SCREEN_GADGETS                     24
+
+#define NUM_SCREEN_SCROLLBUTTONS               2
+#define NUM_SCREEN_SCROLLBARS                  1
+#define NUM_SCREEN_TEXTINPUT                   1
+
+#define SCREEN_MASK_MAIN                       (1 << 0)
+#define SCREEN_MASK_MAIN_HAS_SOLUTION          (1 << 1)
+#define SCREEN_MASK_MAIN_HAS_SET_INFO          (1 << 2)
+#define SCREEN_MASK_INPUT                      (1 << 3)
+#define SCREEN_MASK_TOUCH                      (1 << 4)
+#define SCREEN_MASK_TOUCH2                     (1 << 5)
+#define SCREEN_MASK_SCORES                     (1 << 6)
+#define SCREEN_MASK_SCORES_INFO                        (1 << 7)
 
 // graphic position and size values for buttons and scrollbars
-#define SC_MENUBUTTON_XSIZE            TILEX
-#define SC_MENUBUTTON_YSIZE            TILEY
+#define SC_MENUBUTTON_XSIZE                    TILEX
+#define SC_MENUBUTTON_YSIZE                    TILEY
 
-#define SC_SCROLLBUTTON_XSIZE          TILEX
-#define SC_SCROLLBUTTON_YSIZE          TILEY
+#define SC_SCROLLBUTTON_XSIZE                  TILEX
+#define SC_SCROLLBUTTON_YSIZE                  TILEY
 
-#define SC_SCROLLBAR_XPOS              (SXSIZE - SC_SCROLLBUTTON_XSIZE)
+#define SC_SCROLLBAR_XPOS                      (SXSIZE - SC_SCROLLBUTTON_XSIZE)
 
-#define SC_SCROLL_VERTICAL_XSIZE       SC_SCROLLBUTTON_XSIZE
-#define SC_SCROLL_VERTICAL_YSIZE       ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
-                                        SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_VERTICAL_XSIZE               SC_SCROLLBUTTON_XSIZE
+#define SC_SCROLL_VERTICAL_YSIZE               ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
+                                                SC_SCROLLBUTTON_YSIZE)
 
-#define SC_SCROLL_UP_XPOS              SC_SCROLLBAR_XPOS
-#define SC_SCROLL_UP_YPOS              (2 * SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_UP_XPOS                      SC_SCROLLBAR_XPOS
+#define SC_SCROLL_UP_YPOS                      (2 * SC_SCROLLBUTTON_YSIZE)
 
-#define SC_SCROLL_VERTICAL_XPOS                SC_SCROLLBAR_XPOS
-#define SC_SCROLL_VERTICAL_YPOS                (SC_SCROLL_UP_YPOS + \
-                                        SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_VERTICAL_XPOS                        SC_SCROLLBAR_XPOS
+#define SC_SCROLL_VERTICAL_YPOS                        (SC_SCROLL_UP_YPOS + \
+                                                SC_SCROLLBUTTON_YSIZE)
 
-#define SC_SCROLL_DOWN_XPOS            SC_SCROLLBAR_XPOS
-#define SC_SCROLL_DOWN_YPOS            (SC_SCROLL_VERTICAL_YPOS + \
-                                        SC_SCROLL_VERTICAL_YSIZE)
+#define SC_SCROLL_DOWN_XPOS                    SC_SCROLLBAR_XPOS
+#define SC_SCROLL_DOWN_YPOS                    (SC_SCROLL_VERTICAL_YPOS + \
+                                                SC_SCROLL_VERTICAL_YSIZE)
 
-#define SC_BORDER_SIZE                 14
+#define SC_BORDER_SIZE                         14
 
 
 // forward declarations of internal functions
@@ -250,6 +299,7 @@ static void ConfigureJoystick(int);
 static void ConfigureVirtualButtons(void);
 static void execSetupGame(void);
 static void execSetupEngines(void);
+static void execSetupEditor(void);
 static void execSetupGraphics(void);
 static void execSetupSound(void);
 static void execSetupTouch(void);
@@ -259,6 +309,8 @@ static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
 static void DrawChoosePlayerName(void);
 static void DrawChooseLevelSet(void);
 static void DrawChooseLevelNr(void);
+static void DrawScoreInfo(int);
+static void DrawScoreInfo_Content(int);
 static void DrawInfoScreen(void);
 static void DrawSetupScreen(void);
 static void DrawTypeName(void);
@@ -267,31 +319,48 @@ static void DrawInfoScreen_NotAvailable(char *, char *);
 static void DrawInfoScreen_HelpAnim(int, int, boolean);
 static void DrawInfoScreen_HelpText(int, int, int, int);
 static void HandleInfoScreen_Main(int, int, int, int, int);
-static void HandleInfoScreen_TitleScreen(int);
-static void HandleInfoScreen_Elements(int);
-static void HandleInfoScreen_Music(int);
-static void HandleInfoScreen_Credits(int);
-static void HandleInfoScreen_Program(int);
+static void HandleInfoScreen_TitleScreen(int, int, int);
+static void HandleInfoScreen_Elements(int, int, int);
+static void HandleInfoScreen_Music(int, int, int);
 static void HandleInfoScreen_Version(int);
+static void HandleInfoScreen_Generic(int, int, int);
 
 static void ModifyGameSpeedIfNeeded(void);
 static void DisableVsyncIfNeeded(void);
 
+static void RedrawScreenMenuGadgets(int);
 static void MapScreenMenuGadgets(int);
 static void UnmapScreenMenuGadgets(int);
 static void MapScreenGadgets(int);
+static void UnmapScreenGadgets(void);
 static void MapScreenTreeGadgets(TreeInfo *);
+static void UnmapScreenTreeGadgets(void);
 
 static void UpdateScreenMenuGadgets(int, boolean);
+static void AdjustScoreInfoButtons_SelectScore(int, int, int);
+static void AdjustScoreInfoButtons_PlayTape(int, int, boolean);
 
 static boolean OfferUploadTapes(void);
 static void execOfferUploadTapes(void);
 
+static void DrawHallOfFame_setScoreEntries(void);
+static void HandleHallOfFame_SelectLevel(int, int);
+static char *getHallOfFameRankText(int, int);
+static char *getHallOfFameScoreText(int, int);
+static char *getInfoScreenTitle_Generic(void);
+static int getInfoScreenBackgroundImage_Generic(void);
+static int getInfoScreenBackgroundSound_Generic(void);
+static int getInfoScreenBackgroundMusic_Generic(void);
+
+static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *);
+
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 
 static int info_mode = INFO_MODE_MAIN;
 static int setup_mode = SETUP_MODE_MAIN;
 
+static boolean info_screens_from_main = FALSE;
+
 static TreeInfo *window_sizes = NULL;
 static TreeInfo *window_size_current = NULL;
 
@@ -310,6 +379,21 @@ static TreeInfo *scroll_delay_current = NULL;
 static TreeInfo *snapshot_modes = NULL;
 static TreeInfo *snapshot_mode_current = NULL;
 
+static TreeInfo *game_engine_types = NULL;
+static TreeInfo *game_engine_type_current = NULL;
+
+static TreeInfo *bd_palettes_c64 = NULL;
+static TreeInfo *bd_palette_c64_current = NULL;
+
+static TreeInfo *bd_palettes_c64dtv = NULL;
+static TreeInfo *bd_palette_c64dtv_current = NULL;
+
+static TreeInfo *bd_palettes_atari = NULL;
+static TreeInfo *bd_palette_atari_current = NULL;
+
+static TreeInfo *bd_color_types = NULL;
+static TreeInfo *bd_color_type_current = NULL;
+
 static TreeInfo *scores_types = NULL;
 static TreeInfo *scores_type_current = NULL;
 
@@ -348,276 +432,339 @@ static TreeInfo *player_name_current = NULL;
 static TreeInfo *level_number = NULL;
 static TreeInfo *level_number_current = NULL;
 
+static TreeInfo *score_entries = NULL;
+static TreeInfo *score_entry_current = NULL;
+
 static struct ValueTextInfo window_sizes_list[] =
 {
-  {    50,     "50 %"                          },
-  {    80,     "80 %"                          },
-  {    90,     "90 %"                          },
-  {    100,    "100 % (Default)"               },
-  {    110,    "110 %"                         },
-  {    120,    "120 %"                         },
-  {    130,    "130 %"                         },
-  {    140,    "140 %"                         },
-  {    150,    "150 %"                         },
-  {    200,    "200 %"                         },
-  {    250,    "250 %"                         },
-  {    300,    "300 %"                         },
-
-  {    -1,     NULL                            },
+  { 50,                                        "50 %"                          },
+  { 80,                                        "80 %"                          },
+  { 90,                                        "90 %"                          },
+  { 100,                               "100 % (Default)"               },
+  { 110,                               "110 %"                         },
+  { 120,                               "120 %"                         },
+  { 130,                               "130 %"                         },
+  { 140,                               "140 %"                         },
+  { 150,                               "150 %"                         },
+  { 200,                               "200 %"                         },
+  { 250,                               "250 %"                         },
+  { 300,                               "300 %"                         },
+
+  { -1,                                        NULL                            },
 };
 
 static struct StringValueTextInfo scaling_types_list[] =
 {
-  {    SCALING_QUALITY_NEAREST, "Off"          },
-  {    SCALING_QUALITY_LINEAR,  "Linear"       },
-  {    SCALING_QUALITY_BEST,    "Anisotropic"  },
+  { SCALING_QUALITY_NEAREST,            "Off"                          },
+  { SCALING_QUALITY_LINEAR,             "Linear"                       },
+  { SCALING_QUALITY_BEST,               "Anisotropic"                  },
 
-  {    NULL,                    NULL           },
+  { NULL,                               NULL                           },
 };
 
 static struct StringValueTextInfo rendering_modes_list[] =
 {
-  {    STR_SPECIAL_RENDERING_OFF,      "Off (May show artifacts, fast)" },
-  {    STR_SPECIAL_RENDERING_BITMAP,   "Bitmap/Texture mode (slower)"   },
+  { STR_SPECIAL_RENDERING_OFF,         "Off (May show artifacts, fast)"},
+  { STR_SPECIAL_RENDERING_BITMAP,      "Bitmap/Texture mode (slower)"  },
 #if DEBUG
   // this mode may work under certain conditions, but does not work on Windows
-  {    STR_SPECIAL_RENDERING_TARGET,   "Target Texture mode (slower)"   },
+  { STR_SPECIAL_RENDERING_TARGET,      "Target Texture mode (slower)"  },
 #endif
-  {    STR_SPECIAL_RENDERING_DOUBLE,   "Double Texture mode (slower)"   },
+  { STR_SPECIAL_RENDERING_DOUBLE,      "Double Texture mode (slower)"  },
 
-  {    NULL,                            NULL                            },
+  { NULL,                               NULL                           },
 };
 
 static struct StringValueTextInfo vsync_modes_list[] =
 {
-  {    STR_VSYNC_MODE_OFF,             "Off"           },
-  {    STR_VSYNC_MODE_NORMAL,          "Normal"        },
-  {    STR_VSYNC_MODE_ADAPTIVE,        "Adaptive"      },
+  { STR_VSYNC_MODE_OFF,                        "Off"                           },
+  { STR_VSYNC_MODE_NORMAL,             "Normal"                        },
+  { STR_VSYNC_MODE_ADAPTIVE,           "Adaptive"                      },
 
-  {    NULL,                            NULL           },
+  { NULL,                              NULL                            },
 };
 
 static struct StringValueTextInfo scores_types_list[] =
 {
-  {    STR_SCORES_TYPE_LOCAL_ONLY,         "Local scores only"         },
-  {    STR_SCORES_TYPE_SERVER_ONLY,        "Server scores only"        },
-  {    STR_SCORES_TYPE_LOCAL_AND_SERVER,   "Local and server scores"   },
+  { STR_SCORES_TYPE_LOCAL_ONLY,                "Local scores only"             },
+  { STR_SCORES_TYPE_SERVER_ONLY,       "Server scores only"            },
+  { STR_SCORES_TYPE_LOCAL_AND_SERVER,  "Local and server scores"       },
 
-  {    NULL,                           NULL            },
+  { NULL,                              NULL                            },
 };
 
 static struct ValueTextInfo game_speeds_list_normal[] =
 {
-  {    30,     "Very Slow"                     },
-  {    25,     "Slow"                          },
-  {    20,     "Normal"                        },
-  {    15,     "Fast"                          },
-  {    10,     "Very Fast"                     },
+  { 30,                                        "Very Slow"                     },
+  { 25,                                        "Slow"                          },
+  { 20,                                        "Normal"                        },
+  { 15,                                        "Fast"                          },
+  { 10,                                        "Very Fast"                     },
 
-  {    -1,     NULL                            },
+  { -1,                                        NULL                            },
 };
 
 static struct ValueTextInfo game_speeds_list_extended[] =
 {
-  {    1000,   "1 fps (Extremely Slow)"        },
-  {    500,    "2 fps"                         },
-  {    200,    "5 fps"                         },
-  {    100,    "10 fps"                        },
-  {    50,     "20 fps"                        },
-  {    29,     "35 fps (Original Supaplex)"    },
-  {    25,     "40 fps"                        },
-  {    20,     "50 fps (=== Normal Speed ===)" },
-  {    16,     "60 fps (60 Hz VSync Speed)"    },
-  {    14,     "70 fps (Maximum Supaplex)"     },
-  {    10,     "100 fps"                       },
-  {    5,      "200 fps"                       },
-  {    2,      "500 fps"                       },
-  {    1,      "1000 fps (Extremely Fast)"     },
-
-  {    -1,     NULL                            },
+  { 1000,                              "1 fps (Extremely Slow)"        },
+  { 500,                               "2 fps"                         },
+  { 200,                               "5 fps"                         },
+  { 100,                               "10 fps"                        },
+  { 50,                                        "20 fps"                        },
+  { 29,                                        "35 fps (Original Supaplex)"    },
+  { 25,                                        "40 fps"                        },
+  { 20,                                        "50 fps (=== Normal Speed ===)" },
+  { 16,                                        "60 fps (60 Hz VSync Speed)"    },
+  { 14,                                        "70 fps (Maximum Supaplex)"     },
+  { 10,                                        "100 fps"                       },
+  { 5,                                 "200 fps"                       },
+  { 2,                                 "500 fps"                       },
+  { 1,                                 "1000 fps (Extremely Fast)"     },
+
+  { -1,                                        NULL                            },
 };
 
 static struct ValueTextInfo *game_speeds_list;
 
 static struct ValueTextInfo scroll_delays_list[] =
 {
-  {    0,      "0 Tiles (No Scroll Delay)"     },
-  {    1,      "1 Tile"                        },
-  {    2,      "2 Tiles"                       },
-  {    3,      "3 Tiles (Default)"             },
-  {    4,      "4 Tiles"                       },
-  {    5,      "5 Tiles"                       },
-  {    6,      "6 Tiles"                       },
-  {    7,      "7 Tiles"                       },
-  {    8,      "8 Tiles (Maximum Scroll Delay)"},
-
-  {    -1,     NULL                            },
+  { 0,                                 "0 Tiles (No Scroll Delay)"     },
+  { 1,                                 "1 Tile"                        },
+  { 2,                                 "2 Tiles"                       },
+  { 3,                                 "3 Tiles (Default)"             },
+  { 4,                                 "4 Tiles"                       },
+  { 5,                                 "5 Tiles"                       },
+  { 6,                                 "6 Tiles"                       },
+  { 7,                                 "7 Tiles"                       },
+  { 8,                                 "8 Tiles (Maximum Scroll Delay)"},
+
+  { -1,                                        NULL                            },
 };
 
 static struct StringValueTextInfo snapshot_modes_list[] =
 {
-  {    STR_SNAPSHOT_MODE_OFF,                  "Off"           },
-  {    STR_SNAPSHOT_MODE_EVERY_STEP,           "Every Step"    },
-  {    STR_SNAPSHOT_MODE_EVERY_MOVE,           "Every Move"    },
-  {    STR_SNAPSHOT_MODE_EVERY_COLLECT,        "Every Collect" },
+  { STR_SNAPSHOT_MODE_OFF,             "Off"                           },
+  { STR_SNAPSHOT_MODE_EVERY_STEP,      "Every Step"                    },
+  { STR_SNAPSHOT_MODE_EVERY_MOVE,      "Every Move"                    },
+  { STR_SNAPSHOT_MODE_EVERY_COLLECT,   "Every Collect"                 },
+
+  { NULL,                              NULL                            },
+};
+
+static struct ValueTextInfo game_engine_types_list[] =
+{
+  { GAME_ENGINE_TYPE_RND,              "Rocks'n'Diamonds"              },
+  { GAME_ENGINE_TYPE_BD,               "Boulder Dash"                  },
+  { GAME_ENGINE_TYPE_EM,               "Emerald Mine"                  },
+  { GAME_ENGINE_TYPE_SP,               "Supaplex"                      },
+  { GAME_ENGINE_TYPE_MM,               "Mirror Magic"                  },
+
+  { -1,                                        NULL                            }
+};
+
+static struct ValueTextInfo bd_palettes_c64_list[] =
+{
+  { GD_PALETTE_C64_VICE_NEW,           "Vice new"                      },
+  { GD_PALETTE_C64_VICE_OLD,           "Vice old"                      },
+  { GD_PALETTE_C64_VIDE_DEFAULT,       "Vice default"                  },
+  { GD_PALETTE_C64_C64HQ,              "C64HQ"                         },
+  { GD_PALETTE_C64_C64S,               "C64S"                          },
+  { GD_PALETTE_C64_CCS64,              "CCS64"                         },
+  { GD_PALETTE_C64_FRODO,              "Frodo"                         },
+  { GD_PALETTE_C64_GODOT,              "GoDot"                         },
+  { GD_PALETTE_C64_PC64,               "PC64"                          },
+  { GD_PALETTE_C64_RTADASH,            "RTADash"                       },
+
+  { -1,                                        NULL                            },
+};
+
+static struct ValueTextInfo bd_palettes_c64dtv_list[] =
+{
+  { GD_PALETTE_C64DTV_SPIFF,           "Spiff"                         },
+  { GD_PALETTE_C64DTV_MURRAY,          "Murray"                        },
+
+  { -1,                                        NULL                            },
+};
+
+static struct ValueTextInfo bd_palettes_atari_list[] =
+{
+  { GD_PALETTE_ATARI_BUILTIN,          "BuiltIn"                       },
+  { GD_PALETTE_ATARI_BUILTIN_CONTRAST, "BuiltIn contrast"              },
+  { GD_PALETTE_ATARI_DEFAULT,          "Default"                       },
+  { GD_PALETTE_ATARI_JAKUB,            "Jakub"                         },
+  { GD_PALETTE_ATARI_JAKUB_CONTRAST,   "Jakub contrast"                },
+  { GD_PALETTE_ATARI_REAL,             "Real"                          },
+  { GD_PALETTE_ATARI_REAL_CONTRAST,    "Real contrast"                 },
+  { GD_PALETTE_ATARI_XFORMER,          "XFormer"                       },
+
+  { -1,                                        NULL                            },
+};
+
+static struct ValueTextInfo bd_color_types_list[] =
+{
+  { GD_COLOR_TYPE_RGB,                 "RGB colors"                    },
+  { GD_COLOR_TYPE_C64,                 "C64 colors"                    },
+  { GD_COLOR_TYPE_C64DTV,              "C64DTV colors"                 },
+  { GD_COLOR_TYPE_ATARI,               "Atari colors"                  },
 
-  {    NULL,                                   NULL            },
+  { -1,                                        NULL                            },
 };
 
 static struct ValueTextInfo volumes_list[] =
 {
-  {    0,      "0 %"                           },
-  {    1,      "1 %"                           },
-  {    2,      "2 %"                           },
-  {    5,      "5 %"                           },
-  {    10,     "10 %"                          },
-  {    20,     "20 %"                          },
-  {    30,     "30 %"                          },
-  {    40,     "40 %"                          },
-  {    50,     "50 %"                          },
-  {    60,     "60 %"                          },
-  {    70,     "70 %"                          },
-  {    80,     "80 %"                          },
-  {    90,     "90 %"                          },
-  {    100,    "100 %"                         },
-
-  {    -1,     NULL                            },
+  { 0,                                 "0 %"                           },
+  { 1,                                 "1 %"                           },
+  { 2,                                 "2 %"                           },
+  { 5,                                 "5 %"                           },
+  { 10,                                        "10 %"                          },
+  { 20,                                        "20 %"                          },
+  { 30,                                        "30 %"                          },
+  { 40,                                        "40 %"                          },
+  { 50,                                        "50 %"                          },
+  { 60,                                        "60 %"                          },
+  { 70,                                        "70 %"                          },
+  { 80,                                        "80 %"                          },
+  { 90,                                        "90 %"                          },
+  { 100,                               "100 %"                         },
+
+  { -1,                                        NULL                            },
 };
 
 static struct StringValueTextInfo touch_controls_list[] =
 {
-  {    TOUCH_CONTROL_OFF,              "Off"                   },
-  {    TOUCH_CONTROL_VIRTUAL_BUTTONS,  "Virtual Buttons"       },
-  {    TOUCH_CONTROL_WIPE_GESTURES,    "Wipe Gestures"         },
-  {    TOUCH_CONTROL_FOLLOW_FINGER,    "Follow Finger"         },
+  { TOUCH_CONTROL_OFF,                 "Off"                           },
+  { TOUCH_CONTROL_VIRTUAL_BUTTONS,     "Virtual Buttons"               },
+  { TOUCH_CONTROL_WIPE_GESTURES,       "Wipe Gestures"                 },
+  { TOUCH_CONTROL_FOLLOW_FINGER,       "Follow Finger"                 },
 
-  {    NULL,                           NULL                    },
+  { NULL,                              NULL                            },
 };
 
 static struct ValueTextInfo distances_list[] =
 {
-  {    1,      "1 %"                           },
-  {    2,      "2 %"                           },
-  {    3,      "3 %"                           },
-  {    4,      "4 %"                           },
-  {    5,      "5 %"                           },
-  {    10,     "10 %"                          },
-  {    15,     "15 %"                          },
-  {    20,     "20 %"                          },
-  {    25,     "25 %"                          },
-
-  {    -1,     NULL                            },
+  { 1,                                 "1 %"                           },
+  { 2,                                 "2 %"                           },
+  { 3,                                 "3 %"                           },
+  { 4,                                 "4 %"                           },
+  { 5,                                 "5 %"                           },
+  { 10,                                        "10 %"                          },
+  { 15,                                        "15 %"                          },
+  { 20,                                        "20 %"                          },
+  { 25,                                        "25 %"                          },
+
+  { -1,                                        NULL                            },
 };
 
 static struct ValueTextInfo transparencies_list[] =
 {
-  {    0,      "0 % (Opaque)"                  },
-  {    10,     "10 %"                          },
-  {    20,     "20 %"                          },
-  {    30,     "30 %"                          },
-  {    40,     "40 %"                          },
-  {    50,     "50 %"                          },
-  {    60,     "60 %"                          },
-  {    70,     "70 %"                          },
-  {    80,     "80 %"                          },
-  {    90,     "90 %"                          },
-  {    100,    "100 % (Invisible)"             },
-
-  {    -1,     NULL                            },
+  { 0,                                 "0 % (Opaque)"                  },
+  { 10,                                        "10 %"                          },
+  { 20,                                        "20 %"                          },
+  { 30,                                        "30 %"                          },
+  { 40,                                        "40 %"                          },
+  { 50,                                        "50 %"                          },
+  { 60,                                        "60 %"                          },
+  { 70,                                        "70 %"                          },
+  { 80,                                        "80 %"                          },
+  { 90,                                        "90 %"                          },
+  { 100,                               "100 % (Invisible)"             },
+
+  { -1,                                        NULL                            },
 };
 
 static struct ValueTextInfo grid_sizes_list[] =
 {
-  {    3,      "3"                             },
-  {    4,      "4"                             },
-  {    5,      "5"                             },
-  {    6,      "6"                             },
-  {    7,      "7"                             },
-  {    8,      "8"                             },
-  {    9,      "9"                             },
-  {    10,     "10"                            },
-  {    11,     "11"                            },
-  {    12,     "12"                            },
-  {    13,     "13"                            },
-  {    14,     "14"                            },
-  {    15,     "15"                            },
-  {    16,     "16"                            },
-  {    17,     "17"                            },
-  {    18,     "18"                            },
-  {    19,     "19"                            },
-  {    20,     "20"                            },
-  {    21,     "21"                            },
-  {    22,     "22"                            },
-  {    23,     "23"                            },
-  {    24,     "24"                            },
-  {    25,     "25"                            },
-  {    26,     "26"                            },
-  {    27,     "27"                            },
-  {    28,     "28"                            },
-  {    29,     "29"                            },
-  {    30,     "30"                            },
-  {    31,     "31"                            },
-  {    32,     "32"                            },
-
-  {    -1,     NULL                            },
+  { 3,                                 "3"                             },
+  { 4,                                 "4"                             },
+  { 5,                                 "5"                             },
+  { 6,                                 "6"                             },
+  { 7,                                 "7"                             },
+  { 8,                                 "8"                             },
+  { 9,                                 "9"                             },
+  { 10,                                        "10"                            },
+  { 11,                                        "11"                            },
+  { 12,                                        "12"                            },
+  { 13,                                        "13"                            },
+  { 14,                                        "14"                            },
+  { 15,                                        "15"                            },
+  { 16,                                        "16"                            },
+  { 17,                                        "17"                            },
+  { 18,                                        "18"                            },
+  { 19,                                        "19"                            },
+  { 20,                                        "20"                            },
+  { 21,                                        "21"                            },
+  { 22,                                        "22"                            },
+  { 23,                                        "23"                            },
+  { 24,                                        "24"                            },
+  { 25,                                        "25"                            },
+  { 26,                                        "26"                            },
+  { 27,                                        "27"                            },
+  { 28,                                        "28"                            },
+  { 29,                                        "29"                            },
+  { 30,                                        "30"                            },
+  { 31,                                        "31"                            },
+  { 32,                                        "32"                            },
+
+  { -1,                                        NULL                            },
 };
 
 static int align_xoffset = 0;
 static int align_yoffset = 0;
 
-#define DRAW_MODE(s)           ((s) >= GAME_MODE_MAIN &&               \
-                                (s) <= GAME_MODE_SETUP ? (s) :         \
-                                (s) == GAME_MODE_PSEUDO_TYPENAME ?     \
-                                GAME_MODE_MAIN :                       \
-                                (s) == GAME_MODE_PSEUDO_TYPENAMES ?    \
+#define DRAW_MODE(s)           ((s) >= GAME_MODE_MAIN &&                       \
+                                (s) <= GAME_MODE_SETUP ? (s) :                 \
+                                (s) == GAME_MODE_PSEUDO_TYPENAME ?             \
+                                GAME_MODE_MAIN :                               \
+                                (s) == GAME_MODE_PSEUDO_TYPENAMES ?            \
                                 GAME_MODE_NAMES : GAME_MODE_DEFAULT)
 
 // (there are no draw offset definitions needed for INFO_MODE_TITLE)
-#define DRAW_MODE_INFO(i)      ((i) >= INFO_MODE_TITLE &&              \
-                                (i) <= INFO_MODE_LEVELSET ? (i) :      \
+#define DRAW_MODE_INFO(i)      ((i) >= INFO_MODE_TITLE &&                      \
+                                (i) <= INFO_MODE_LEVELSET ? (i) :              \
                                 INFO_MODE_MAIN)
 
-#define DRAW_MODE_SETUP(i)     ((i) >= SETUP_MODE_MAIN &&              \
-                                (i) <= SETUP_MODE_SHORTCUTS_5 ? (i) :  \
-                                (i) >= SETUP_MODE_CHOOSE_GRAPHICS &&   \
-                                (i) <= SETUP_MODE_CHOOSE_MUSIC ?       \
-                                SETUP_MODE_CHOOSE_ARTWORK :            \
+#define DRAW_MODE_SETUP(i)     ((i) >= SETUP_MODE_MAIN &&                      \
+                                (i) <= SETUP_MODE_SHORTCUTS_6 ? (i) :          \
+                                (i) >= SETUP_MODE_CHOOSE_GRAPHICS &&           \
+                                (i) <= SETUP_MODE_CHOOSE_MUSIC ?               \
+                                SETUP_MODE_CHOOSE_ARTWORK :                    \
                                 SETUP_MODE_CHOOSE_OTHER)
 
-#define DRAW_XOFFSET_INFO(i)   (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?  \
-                                menu.draw_xoffset[GAME_MODE_INFO] :    \
+#define DRAW_XOFFSET_INFO(i)   (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?          \
+                                menu.draw_xoffset[GAME_MODE_INFO] :            \
                                 menu.draw_xoffset_info[DRAW_MODE_INFO(i)])
-#define DRAW_YOFFSET_INFO(i)   (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?  \
-                                menu.draw_yoffset[GAME_MODE_INFO] :    \
+#define DRAW_YOFFSET_INFO(i)   (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?          \
+                                menu.draw_yoffset[GAME_MODE_INFO] :            \
                                 menu.draw_yoffset_info[DRAW_MODE_INFO(i)])
-#define EXTRA_SPACING_INFO(i)  (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ? \
-                                menu.extra_spacing[GAME_MODE_INFO] :   \
+#define EXTRA_SPACING_INFO(i)  (DRAW_MODE_INFO(i) == INFO_MODE_MAIN ?          \
+                                menu.extra_spacing[GAME_MODE_INFO] :           \
                                 menu.extra_spacing_info[DRAW_MODE_INFO(i)])
 
-#define DRAW_XOFFSET_SETUP(i)  (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
-                                menu.draw_xoffset[GAME_MODE_SETUP] :   \
+#define DRAW_XOFFSET_SETUP(i)  (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ?        \
+                                menu.draw_xoffset[GAME_MODE_SETUP] :           \
                                 menu.draw_xoffset_setup[DRAW_MODE_SETUP(i)])
-#define DRAW_YOFFSET_SETUP(i)  (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
-                                menu.draw_yoffset[GAME_MODE_SETUP] :   \
+#define DRAW_YOFFSET_SETUP(i)  (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ?        \
+                                menu.draw_yoffset[GAME_MODE_SETUP] :           \
                                 menu.draw_yoffset_setup[DRAW_MODE_SETUP(i)])
-#define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ? \
-                                menu.extra_spacing[GAME_MODE_SETUP] :  \
+#define EXTRA_SPACING_SETUP(i) (DRAW_MODE_SETUP(i) == SETUP_MODE_MAIN ?        \
+                                menu.extra_spacing[GAME_MODE_SETUP] :          \
                                 menu.extra_spacing_setup[DRAW_MODE_SETUP(i)])
 
-#define DRAW_XOFFSET(s)                ((s) == GAME_MODE_INFO ?                \
-                                DRAW_XOFFSET_INFO(info_mode) :         \
-                                (s) == GAME_MODE_SETUP ?               \
-                                DRAW_XOFFSET_SETUP(setup_mode) :       \
+#define EXTRA_SPACING_SCORES(i)        (EXTRA_SPACING_INFO(i))
+
+#define EXTRA_SPACING_SCOREINFO(i) (menu.extra_spacing[GAME_MODE_SCOREINFO])
+
+#define DRAW_XOFFSET(s)                ((s) == GAME_MODE_INFO  ? DRAW_XOFFSET_INFO(info_mode) :        \
+                                (s) == GAME_MODE_SETUP ? DRAW_XOFFSET_SETUP(setup_mode) :      \
                                 menu.draw_xoffset[DRAW_MODE(s)])
-#define DRAW_YOFFSET(s)                ((s) == GAME_MODE_INFO ?                \
-                                DRAW_YOFFSET_INFO(info_mode) :         \
-                                (s) == GAME_MODE_SETUP ?               \
-                                DRAW_YOFFSET_SETUP(setup_mode) :       \
+
+#define DRAW_YOFFSET(s)                ((s) == GAME_MODE_INFO  ? DRAW_YOFFSET_INFO(info_mode) :        \
+                                (s) == GAME_MODE_SETUP ? DRAW_YOFFSET_SETUP(setup_mode) :      \
                                 menu.draw_yoffset[DRAW_MODE(s)])
-#define EXTRA_SPACING(s)       ((s) == GAME_MODE_INFO ?                \
-                                EXTRA_SPACING_INFO(info_mode) :        \
-                                (s) == GAME_MODE_SETUP ?               \
-                                EXTRA_SPACING_SETUP(setup_mode) :      \
+
+#define EXTRA_SPACING(s)       ((s) == GAME_MODE_INFO   ? EXTRA_SPACING_INFO(info_mode) :      \
+                                (s) == GAME_MODE_SETUP  ? EXTRA_SPACING_SETUP(setup_mode) :    \
+                                (s) == GAME_MODE_SCORES ? EXTRA_SPACING_SCORES(info_mode) :    \
                                 menu.extra_spacing[DRAW_MODE(s)])
 
 #define mSX                    (SX + DRAW_XOFFSET(game_status))
@@ -630,14 +777,12 @@ static int align_yoffset = 0;
                                    menu.list_size[game_status] :       \
                                    MAX_MENU_ENTRIES_ON_SCREEN)
 
-#define IN_VIS_MENU(x, y)      IN_FIELD(x, y, SCR_FIELDX,              \
-                                        NUM_MENU_ENTRIES_ON_SCREEN)
+#define IN_VIS_MENU(x, y)      IN_FIELD(x, y, SCR_FIELDX, NUM_MENU_ENTRIES_ON_SCREEN)
 
 
 // title display and control definitions
 
-#define MAX_NUM_TITLE_SCREENS  (2 * MAX_NUM_TITLE_IMAGES +             \
-                                2 * MAX_NUM_TITLE_MESSAGES)
+#define MAX_NUM_TITLE_SCREENS  (2 * MAX_NUM_TITLE_IMAGES + 2 * MAX_NUM_TITLE_MESSAGES)
 
 #define NO_DIRECT_LEVEL_SELECT (-1)
 
@@ -655,6 +800,7 @@ struct TitleControlInfo
 
 struct TitleControlInfo title_controls[MAX_NUM_TITLE_SCREENS];
 
+
 // main menu display and control definitions
 
 #define MAIN_CONTROL_NAME                      0
@@ -882,6 +1028,11 @@ static struct MainControlInfo main_controls[] =
 };
 
 
+static boolean hasLevelSetInfo(void)
+{
+  return (getLevelSetInfoFilename(0) != NULL);
+}
+
 static int getTitleScreenGraphic(int nr, boolean initial)
 {
   return (initial ? IMG_TITLESCREEN_INITIAL_1 : IMG_TITLESCREEN_1) + nr;
@@ -1054,6 +1205,27 @@ static int compareTitleControlInfo(const void *object1, const void *object2)
   return compare_result;
 }
 
+static boolean CheckTitleScreen_BD(int nr, boolean initial)
+{
+  // only show BD style title screen for native BD level sets
+  if (level.game_engine_type != GAME_ENGINE_TYPE_BD)
+    return FALSE;
+
+  // only show BD style title screen for first title screen of a level set
+  if (initial || nr != 0)
+    return FALSE;
+
+  int graphic = getTitleScreenGraphic(nr, initial);
+  Bitmap *bitmap = graphic_info[graphic].bitmap;
+
+  // only show BD style title screen if no other title screen defined
+  if (bitmap != NULL)
+    return FALSE;
+
+  // check if BD style title screen defined
+  return (GetTitleScreenBitmaps_BD() != NULL);
+}
+
 static void InitializeTitleControlsExt_AddTitleInfo(boolean is_image,
                                                    boolean initial,
                                                    int nr, int sort_priority)
@@ -1077,8 +1249,13 @@ static void InitializeTitleControls_CheckTitleInfo(boolean initial)
     int graphic = getTitleScreenGraphic(i, initial);
     Bitmap *bitmap = graphic_info[graphic].bitmap;
     int sort_priority = graphic_info[graphic].sort_priority;
+    boolean has_title_screen = (bitmap != NULL);
 
-    if (bitmap != NULL)
+    // check for optional title screen of native BD style level set
+    if (CheckTitleScreen_BD(i, initial))
+      has_title_screen = TRUE;
+
+    if (has_title_screen)
       InitializeTitleControlsExt_AddTitleInfo(TRUE, initial, i, sort_priority);
   }
 
@@ -1393,10 +1570,10 @@ static void AdjustScrollbar(int id, int items_max, int items_visible,
               GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
 }
 
-static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
+static void AdjustChooseTreeScrollbar(TreeInfo *ti, int id)
 {
   AdjustScrollbar(id, numTreeInfoInGroup(ti), NUM_MENU_ENTRIES_ON_SCREEN,
-                 first_entry);
+                 ti->cl_first);
 }
 
 static void clearMenuListArea(void)
@@ -1410,6 +1587,11 @@ static void clearMenuListArea(void)
   // clear menu list area, but not title or scrollbar
   DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
                  scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
+
+  // special compatibility handling for "Snake Bite" graphics set
+  if (strPrefix(leveldir_current->identifier, "snake_bite"))
+    ClearRectangle(drawto, mSX, mSY + MENU_SCREEN_START_YPOS * 32,
+                  scrollbar_xpos - mSX, NUM_MENU_ENTRIES_ON_SCREEN * 32);
 }
 
 static void drawCursorExt(int xpos, int ypos, boolean active, int graphic)
@@ -1478,6 +1660,15 @@ static int getChooseTreeEditYPos(int ypos_raw)
   return sy;
 }
 
+static int getChooseTreeEditXPosReal(int pos)
+{
+  int xpos = getChooseTreeEditXPos(pos);
+  int font_nr = getChooseTreeEditFont(FALSE);
+  int font_xoffset = getFontDrawOffsetX(font_nr);
+
+  return xpos + font_xoffset;
+}
+
 static void drawChooseTreeEdit(int ypos_raw, boolean active)
 {
   int sx = getChooseTreeEditXPos(POS_LEFT);
@@ -1487,22 +1678,64 @@ static void drawChooseTreeEdit(int ypos_raw, boolean active)
   DrawText(sx, sy, STR_CHOOSE_TREE_EDIT, font_nr);
 }
 
-static void DrawHeadline(void)
+static void DrawInfoScreen_Headline(int screen_nr, int num_screens,
+                                   int use_global_screens)
 {
-  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, main_text_title_1);
-  DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, main_text_title_2);
+  char *info_text_title_1 = getInfoScreenTitle_Generic();
+  char info_text_title_2[MAX_LINE_LEN + 1];
+
+  if (num_screens > 1)
+  {
+    sprintf(info_text_title_2, "Page %d of %d", screen_nr + 1, num_screens);
+  }
+  else
+  {
+    char *text_format = (use_global_screens ? "for %s" : "for \"%s\"");
+    int text_format_len = strlen(text_format) - strlen("%s");
+    int max_text_len = SXSIZE / getFontWidth(FONT_TITLE_2);
+    int max_name_len = max_text_len - text_format_len;
+    char name_cut[max_name_len];
+    char *name_full = (use_global_screens ? getProgramTitleString() :
+                      leveldir_current->name);
+
+    snprintf(name_cut, max_name_len, "%s", name_full);
+    snprintf(info_text_title_2, max_text_len, text_format, name_cut);
+  }
+
+  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, info_text_title_1);
+  DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, info_text_title_2);
 }
 
 static void DrawTitleScreenImage(int nr, boolean initial)
 {
+  static int frame_counter = 0;
   int graphic = getTitleScreenGraphic(nr, initial);
   Bitmap *bitmap = graphic_info[graphic].bitmap;
+  Bitmap *bitmap_background = NULL;
+  int draw_masked = graphic_info[graphic].draw_masked;
   int width  = graphic_info[graphic].width;
   int height = graphic_info[graphic].height;
   int src_x = graphic_info[graphic].src_x;
   int src_y = graphic_info[graphic].src_y;
   int dst_x, dst_y;
 
+  // check for optional title screen of native BD style level set
+  if (CheckTitleScreen_BD(nr, initial))
+  {
+    Bitmap **title_screen_bitmaps = GetTitleScreenBitmaps_BD();
+
+    bitmap            = title_screen_bitmaps[0];
+    bitmap_background = title_screen_bitmaps[1];
+
+    if (bitmap != NULL)
+    {
+      width  = bitmap->width;
+      height = bitmap->height;
+      src_x = 0;
+      src_y = 0;
+    }
+  }
+
   if (bitmap == NULL)
     return;
 
@@ -1529,7 +1762,19 @@ static void DrawTitleScreenImage(int nr, boolean initial)
 
   ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
-  if (DrawingOnBackground(dst_x, dst_y))
+  boolean draw_masked_final = (DrawingOnBackground(dst_x, dst_y) && draw_masked);
+
+  if (bitmap_background != NULL)
+  {
+    int size = bitmap_background->height - bitmap->height;
+    int offset = frame_counter++ % size;
+
+    BlitBitmap(bitmap_background, drawto, src_x, src_y + offset, width, height, dst_x, dst_y);
+
+    draw_masked_final = TRUE;
+  }
+
+  if (draw_masked_final)
     BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
   else
     BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
@@ -1647,11 +1892,31 @@ void DrawMainMenu(void)
     return;
   }
 
+  // needed if last screen was the playing screen, invoked from hall of fame
+  if (score_info_tape_play)
+  {
+    CloseDoor(DOOR_CLOSE_ALL);
+
+    SetGameStatus(GAME_MODE_SCOREINFO);
+
+    DrawScoreInfo(scores.last_entry_nr);
+
+    return;
+  }
+
+  // reset flag to continue playing next level from hall of fame
+  scores.continue_playing = FALSE;
+
   // leveldir_current may be invalid (level group, parent link, node copy)
   leveldir_current = getValidLevelSeries(leveldir_current, leveldir_last_valid);
 
   if (leveldir_current != leveldir_last_valid)
   {
+    // level setup config may have been loaded to "last played" tree node copy,
+    // but "leveldir_current" now points to the "original" level set tree node,
+    // in which case "handicap_level" may still default to the first level
+    LoadLevelSetup_SeriesInfo();
+
     UpdateLastPlayedLevels_TreeInfo();
 
     levelset_has_changed = TRUE;
@@ -1660,7 +1925,17 @@ void DrawMainMenu(void)
   // store valid level series information
   leveldir_last_valid = leveldir_current;
 
-  init_last = init;                    // switch to new busy animation
+  // store first level of this level set for "level_nr" style animations
+  SetAnimationFirstLevel(leveldir_current->first_level);
+
+  // level_nr may have been set to value over handicap with level editor
+  if (setup.allow_skipping_levels != STATE_TRUE && level_nr > leveldir_current->handicap_level)
+    level_nr = leveldir_current->handicap_level;
+
+  LoadLevel(level_nr);
+  LoadScore(level_nr);
+
+  SaveLevelSetup_SeriesInfo();
 
   // needed if last screen (level choice) changed graphics, sounds or music
   ReloadCustomArtwork(0);
@@ -1687,15 +1962,6 @@ void DrawMainMenu(void)
 
   SetDrawtoField(DRAW_TO_BACKBUFFER);
 
-  // level_nr may have been set to value over handicap with level editor
-  if (setup.handicap && level_nr > leveldir_current->handicap_level)
-    level_nr = leveldir_current->handicap_level;
-
-  LoadLevel(level_nr);
-  LoadScore(level_nr);
-
-  SaveLevelSetup_SeriesInfo();
-
   // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
   SetDrawDeactivationMask(REDRAW_NONE);
   SetDrawBackgroundMask(REDRAW_FIELD);
@@ -1736,6 +2002,7 @@ void DrawMainMenu(void)
   MapTapeButtons();
   MapScreenMenuGadgets(SCREEN_MASK_MAIN);
   UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
+  UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SET_INFO, hasLevelSetInfo());
 
   // copy actual game door content to door double buffer for OpenDoor()
   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
@@ -1758,8 +2025,8 @@ void DrawMainMenu(void)
 
   SyncEmscriptenFilesystem();
 
-  // needed once to upload tapes (after program start or after user change)
-  CheckUploadTapes();
+  // needed once after program start or after user change
+  CheckApiServerTasks();
 }
 
 static void gotoTopLevelDir(void)
@@ -1797,7 +2064,7 @@ static unsigned int getAutoDelayCounter(struct TitleFadingInfo *fi)
 static boolean TitleAutoDelayReached(unsigned int *counter_var,
                                     struct TitleFadingInfo *fi)
 {
-  return DelayReachedExt(counter_var, fi->auto_delay, getAutoDelayCounter(fi));
+  return DelayReachedExt2(counter_var, fi->auto_delay, getAutoDelayCounter(fi));
 }
 
 static void ResetTitleAutoDelay(unsigned int *counter_var,
@@ -1892,7 +2159,7 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
   {
     return_to_main_menu = TRUE;
   }
-  else if (button == MB_MENU_CHOICE)
+  else if (button == MB_MENU_CHOICE || dx)
   {
     if (game_status_last_screen == GAME_MODE_INFO && num_title_screens == 0)
     {
@@ -1905,9 +2172,10 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
       return;
     }
 
-    title_screen_nr++;
+    title_screen_nr +=
+      (game_status_last_screen == GAME_MODE_INFO && dx < 0 ? -1 : +1);
 
-    if (title_screen_nr < num_title_screens)
+    if (title_screen_nr >= 0 && title_screen_nr < num_title_screens)
     {
       tci = &title_controls[title_screen_nr];
 
@@ -1952,6 +2220,21 @@ void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
       return_to_main_menu = TRUE;
     }
   }
+  else
+  {
+    tci = &title_controls[title_screen_nr];
+
+    // check for optional title screen of native BD style level set
+    if (tci->is_image && CheckTitleScreen_BD(tci->local_nr, tci->initial))
+    {
+      Bitmap **title_screen_bitmaps = GetTitleScreenBitmaps_BD();
+
+      // if title screen is animated, draw title screen animation
+      if (title_screen_bitmaps[0] != NULL &&
+         title_screen_bitmaps[1] != NULL)
+       DrawTitleScreenImage(tci->local_nr, tci->initial);
+    }
+  }
 
   if (return_to_main_menu)
   {
@@ -2003,11 +2286,14 @@ static void HandleMainMenu_SelectLevel(int step, int direction,
   if (new_level_nr > leveldir_current->last_level)
     new_level_nr = leveldir_current->last_level;
 
-  if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
+  if (setup.allow_skipping_levels != STATE_TRUE && new_level_nr > leveldir_current->handicap_level)
   {
     // skipping levels is only allowed when trying to skip single level
-    if (setup.skip_levels && new_level_nr == old_level_nr + 1 &&
-       Request("Level still unsolved! Skip despite handicap?", REQ_ASK))
+    // (also, skipping BD style intermission levels is always possible)
+    if (new_level_nr == old_level_nr + 1 &&
+       (level.bd_intermission ||
+        (setup.allow_skipping_levels == STATE_ASK &&
+         Request("Level still unsolved! Skip it anyway?", REQ_ASK))))
     {
       leveldir_current->handicap_level++;
       SaveLevelSetup_SeriesInfo();
@@ -2330,15 +2616,15 @@ static void execExitInfo(void)
 
 static struct TokenInfo info_info_main[] =
 {
-  { TYPE_ENTER_SCREEN, execInfoTitleScreen,    "Title Screen"          },
-  { TYPE_ENTER_SCREEN, execInfoElements,       "Elements Info"         },
-  { TYPE_ENTER_SCREEN, execInfoMusic,          "Music Info"            },
-  { TYPE_ENTER_SCREEN, execInfoCredits,        "Credits"               },
-  { TYPE_ENTER_SCREEN, execInfoProgram,        "Program Info"          },
-  { TYPE_ENTER_SCREEN, execInfoVersion,        "Version Info"          },
-  { TYPE_ENTER_SCREEN, execInfoLevelSet,       "Level Set Info"        },
+  { TYPE_ENTER_SCREEN, execInfoTitleScreen,    STR_INFO_TITLE          },
+  { TYPE_ENTER_SCREEN, execInfoElements,       STR_INFO_ELEMENTS       },
+  { TYPE_ENTER_SCREEN, execInfoMusic,          STR_INFO_MUSIC          },
+  { TYPE_ENTER_SCREEN, execInfoCredits,        STR_INFO_CREDITS        },
+  { TYPE_ENTER_SCREEN, execInfoProgram,        STR_INFO_PROGRAM        },
+  { TYPE_ENTER_SCREEN, execInfoVersion,        STR_INFO_VERSION        },
+  { TYPE_ENTER_SCREEN, execInfoLevelSet,       STR_INFO_LEVELSET       },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execExitInfo,           "Exit"                  },
+  { TYPE_LEAVE_MENU,   execExitInfo,           STR_INFO_EXIT           },
 
   { 0,                 NULL,                   NULL                    }
 };
@@ -2348,6 +2634,7 @@ static int getMenuTextFont(int type)
   if (type & (TYPE_SWITCH      |
              TYPE_YES_NO       |
              TYPE_YES_NO_AUTO  |
+             TYPE_YES_NO_ASK   |
              TYPE_STRING       |
              TYPE_PLAYER       |
              TYPE_ECS_AGA      |
@@ -2364,6 +2651,78 @@ static struct TokenInfo setup_info_input[];
 
 static struct TokenInfo *menu_info;
 
+static void PlayInfoSound(void)
+{
+  int info_sound = getInfoScreenBackgroundSound_Generic();
+  char *next_sound = getSoundInfoEntryFilename(info_sound);
+
+  if (next_sound != NULL)
+    PlayMenuSoundExt(info_sound);
+  else
+    PlayMenuSound();
+}
+
+static void PlayInfoSoundIfLoop(void)
+{
+  int info_sound = getInfoScreenBackgroundSound_Generic();
+  char *next_sound = getSoundInfoEntryFilename(info_sound);
+
+  if (next_sound != NULL)
+    PlayMenuSoundIfLoopExt(info_sound);
+  else
+    PlayMenuSoundIfLoop();
+}
+
+static void PlayInfoMusic(void)
+{
+  int info_music = getInfoScreenBackgroundMusic_Generic();
+  char *curr_music = getCurrentlyPlayingMusicFilename();
+  char *next_music = getMusicInfoEntryFilename(info_music);
+
+  if (next_music != NULL)
+  {
+    // play music if info screen music differs from current music
+    if (!strEqual(curr_music, next_music))
+      PlayMenuMusicExt(info_music);
+  }
+  else
+  {
+    // only needed if info screen was directly invoked from main menu
+    PlayMenuMusic();
+  }
+}
+
+static void PlayInfoSoundsAndMusic(void)
+{
+  PlayInfoSound();
+  PlayInfoMusic();
+}
+
+static void FadeInfoSounds(void)
+{
+  FadeSounds();
+}
+
+static void FadeInfoMusic(void)
+{
+  int info_music = getInfoScreenBackgroundMusic_Generic();
+  char *curr_music = getCurrentlyPlayingMusicFilename();
+  char *next_music = getMusicInfoEntryFilename(info_music);
+
+  if (next_music != NULL)
+  {
+    // fade music if info screen music differs from current music
+    if (!strEqual(curr_music, next_music))
+      FadeMusic();
+  }
+}
+
+static void FadeInfoSoundsAndMusic(void)
+{
+  FadeInfoSounds();
+  FadeInfoMusic();
+}
+
 static void DrawCursorAndText_Menu_Ext(struct TokenInfo *token_info,
                                       int screen_pos, int menu_info_pos_raw,
                                       boolean active)
@@ -2468,6 +2827,18 @@ static void DrawInfoScreen_Main(void)
   int fade_mask = REDRAW_FIELD;
   int i;
 
+  // (needed after displaying info sub-screens directly from main menu)
+  if (info_screens_from_main)
+  {
+    info_screens_from_main = FALSE;
+
+    SetGameStatus(GAME_MODE_MAIN);
+
+    DrawMainMenu();
+
+    return;
+  }
+
   if (redraw_mask & REDRAW_ALL)
     fade_mask = REDRAW_ALL;
 
@@ -2496,10 +2867,13 @@ static void DrawInfoScreen_Main(void)
 
   OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
 
-  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
+  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, STR_INFO_MAIN);
 
   info_info = info_info_main;
 
+  // use modified info screen info without info screen entries marked as hidden
+  info_info = getSetupInfoFinal(info_info);
+
   // determine maximal number of info entries that can be displayed on screen
   num_info_info = 0;
   for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
@@ -2707,6 +3081,7 @@ static void HandleMenuScreen(int mx, int my, int dx, int dy, int button,
       if (menu_info[choice].type & menu_navigation_type ||
          menu_info[choice].type & TYPE_BOOLEAN_STYLE ||
          menu_info[choice].type & TYPE_YES_NO_AUTO ||
+         menu_info[choice].type & TYPE_YES_NO_ASK ||
          menu_info[choice].type & TYPE_PLAYER)
        button = MB_MENU_CHOICE;
     }
@@ -2862,15 +3237,23 @@ static int getMenuTextStep(int spacing_height, int font_nr)
   return getFontHeight(font_nr) + getMenuTextSpacing(spacing_height, font_nr);
 }
 
+static int getHeadlineSpacing(void)
+{
+  // special compatibility handling for "R'n'D jue 2022" game editions
+  int spacing_check = menu.headline1_spacing[GAME_MODE_SCOREINFO];
+  int spacing = (game_status == GAME_MODE_SCOREINFO ?
+                menu.headline1_spacing[GAME_MODE_SCOREINFO] :
+                menu.headline1_spacing_info[info_mode]);
+  int font = MENU_INFO_FONT_TITLE;
+
+  return (spacing_check != -2 ? getMenuTextStep(spacing, font) : 0);
+}
+
 void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
 {
-  int font_title = MENU_INFO_FONT_TITLE;
   int font_error = FONT_TEXT_2;
   int font_foot  = MENU_INFO_FONT_FOOT;
-  int spacing_title = menu.headline1_spacing_info[info_mode];
-  int ystep_title = getMenuTextStep(spacing_title, font_title);
-  int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
-  int ystart2 = ystart1 + ystep_title;
+  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
   int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
 
   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO);
@@ -2878,28 +3261,27 @@ void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
   FadeOut(REDRAW_FIELD);
 
   ClearField();
-  DrawHeadline();
 
-  DrawTextSCentered(ystart1, font_title, text_title);
-  DrawTextSCentered(ystart2, font_error, text_error);
+  DrawInfoScreen_Headline(0, 1, FALSE);
 
-  DrawTextSCentered(ybottom, font_foot,
-                   "Press any key or button for info menu");
+  DrawTextSCentered(ystart, font_error, text_error);
+  DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_MENU);
 
   FadeIn(REDRAW_FIELD);
 }
 
 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
 {
-  static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
-  static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
-  int font_title = MENU_INFO_FONT_TITLE;
-  int font_foot  = MENU_INFO_FONT_FOOT;
-  int xstart  = mSX + MENU_SCREEN_INFO_SPACE_LEFT;
-  int ystart1 = mSY - SY + MENU_SCREEN_INFO_YSTART1;
-  int ystart2 = mSY + MENU_SCREEN_INFO_YSTART2;
+  static int infoscreen_step[MAX_INFO_ELEMENTS_IN_ARRAY];
+  static int infoscreen_frame[MAX_INFO_ELEMENTS_IN_ARRAY];
+  int font_foot = MENU_INFO_FONT_FOOT;
+  int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT;
+  int ystart = mSY + MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
   int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
   int ystep = MENU_SCREEN_INFO_YSTEP;
+  int row_height = MENU_SCREEN_INFO_ENTRY_SIZE;
+  int tilesize = MENU_SCREEN_INFO_TILE_SIZE;
+  int yoffset = (row_height - tilesize) / 2;
   int element, action, direction;
   int graphic;
   int delay;
@@ -2911,13 +3293,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     for (i = 0; i < NUM_INFO_ELEMENTS_ON_SCREEN; i++)
       infoscreen_step[i] = infoscreen_frame[i] = 0;
 
-    ClearField();
-    DrawHeadline();
-
-    DrawTextSCentered(ystart1, font_title, "The Game Elements:");
-
-    DrawTextSCentered(ybottom, font_foot,
-                     "Press any key or button for next page");
+    DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_PAGE);
 
     FrameCounter = 0;
   }
@@ -2939,7 +3315,10 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
       continue;
     }
 
-    j += infoscreen_step[i - start];
+    int ypos = i - start;
+    int ystart_pos = ystart + ypos * ystep + yoffset;
+
+    j += infoscreen_step[ypos];
 
     element = helpanim_info[j].element;
     action = helpanim_info[j].action;
@@ -2962,39 +3341,38 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     if (delay == -1)
       delay = 1000000;
 
-    if (infoscreen_frame[i - start] == 0)
+    if (infoscreen_frame[ypos] == 0)
     {
       sync_frame = 0;
-      infoscreen_frame[i - start] = delay - 1;
+      infoscreen_frame[ypos] = delay - 1;
     }
     else
     {
-      sync_frame = delay - infoscreen_frame[i - start];
-      infoscreen_frame[i - start]--;
+      sync_frame = delay - infoscreen_frame[ypos];
+      infoscreen_frame[ypos]--;
     }
 
     if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
     {
-      if (!infoscreen_frame[i - start])
-       infoscreen_step[i - start] = 0;
+      if (!infoscreen_frame[ypos])
+       infoscreen_step[ypos] = 0;
     }
     else
     {
-      if (!infoscreen_frame[i - start])
-       infoscreen_step[i - start]++;
+      if (!infoscreen_frame[ypos])
+       infoscreen_step[ypos]++;
       while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
        j++;
     }
 
     j++;
 
-    ClearRectangleOnBackground(drawto, xstart, ystart2 + (i - start) * ystep,
-                              TILEX, TILEY);
-    DrawFixedGraphicAnimationExt(drawto, xstart, ystart2 + (i - start) * ystep,
-                                graphic, sync_frame, USE_MASKING);
+    ClearRectangleOnBackground(drawto, xstart, ystart_pos, tilesize, tilesize);
+    DrawSizedGraphicAnimationExt(drawto, xstart, ystart_pos,
+                                graphic, sync_frame, tilesize, USE_MASKING);
 
     if (init)
-      DrawInfoScreen_HelpText(element, action, direction, i - start);
+      DrawInfoScreen_HelpText(element, action, direction, ypos);
 
     i++;
   }
@@ -3024,15 +3402,24 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
   int font_nr = FONT_INFO_ELEMENTS;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
-  int yoffset = (TILEX - 2 * font_height) / 2;
-  int xstart = mSX + MENU_SCREEN_INFO_SPACE_LEFT + TILEX + MINI_TILEX;
-  int ystart = mSY + MENU_SCREEN_INFO_YSTART2 + yoffset;
-  int ystep = TILEY + 4;
+  int line_spacing = MENU_SCREEN_INFO_SPACE_LINE;
+  int left_spacing = MENU_SCREEN_INFO_SPACE_LEFT;
+  int middle_spacing = MENU_SCREEN_INFO_SPACE_MIDDLE;
+  int right_spacing = MENU_SCREEN_INFO_SPACE_RIGHT;
+  int line_height = font_height + line_spacing;
+  int row_height = MENU_SCREEN_INFO_ENTRY_SIZE;
+  int tilesize = MENU_SCREEN_INFO_TILE_SIZE;
+  int xstart = mSX + left_spacing + tilesize + middle_spacing;
+  int ystart = mSY + MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
+  int ystep = MENU_SCREEN_INFO_YSTEP;
   int pad_left = xstart - SX;
-  int pad_right = MENU_SCREEN_INFO_SPACE_RIGHT;
+  int pad_right = right_spacing;
   int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
-  int max_lines_per_text = 2;    
+  int max_lines_per_text = (row_height + line_spacing) / line_height;
   char *text = NULL;
+  boolean autowrap = TRUE;
+  boolean centered = FALSE;
+  boolean parse_comments = FALSE;
 
   if (action != -1 && direction != -1)         // element.action.direction
     text = getHelpText(element, action, direction);
@@ -3049,49 +3436,68 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
   if (text == NULL)                            // not found
     text = "No description available";
 
-  if (strlen(text) <= max_chars_per_line)      // only one line of text
-    ystart += getFontHeight(font_nr) / 2;
+  DisableDrawingText();
+
+  // first get number of text lines to calculate offset for centering text
+  int num_lines_printed =
+    DrawTextBuffer(0, 0, text, font_nr,
+                  max_chars_per_line, -1, max_lines_per_text, line_spacing, -1,
+                  autowrap, centered, parse_comments);
 
-  DrawTextBuffer(xstart, ystart + ypos * ystep, text, font_nr,
-                max_chars_per_line, -1, max_lines_per_text, 0, -1,
-                TRUE, FALSE, FALSE);
+  EnableDrawingText();
+
+  int size_lines_printed = num_lines_printed * line_height - line_spacing;
+  int yoffset = (row_height - size_lines_printed) / 2;
+
+  DrawTextBuffer(xstart, ystart + ypos * ystep + yoffset, text, font_nr,
+                max_chars_per_line, -1, max_lines_per_text, line_spacing, -1,
+                autowrap, centered, parse_comments);
 }
 
 static void DrawInfoScreen_TitleScreen(void)
 {
   SetGameStatus(GAME_MODE_TITLE);
 
+  UnmapAllGadgets();
+
   DrawTitleScreen();
 }
 
-void HandleInfoScreen_TitleScreen(int button)
+void HandleInfoScreen_TitleScreen(int dx, int dy, int button)
 {
-  HandleTitleScreen(0, 0, 0, 0, button);
+  HandleTitleScreen(0, 0, dx, dy, button);
 }
 
 static void DrawInfoScreen_Elements(void)
 {
   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
 
+  UnmapAllGadgets();
+  FadeInfoSoundsAndMusic();
+
   FadeOut(REDRAW_FIELD);
 
   LoadHelpAnimInfo();
   LoadHelpTextInfo();
 
-  HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
+  HandleInfoScreen_Elements(0, 0, MB_MENU_INITIALIZE);
+
+  PlayInfoSoundsAndMusic();
 
   FadeIn(REDRAW_FIELD);
 }
 
-void HandleInfoScreen_Elements(int button)
+void HandleInfoScreen_Elements(int dx, int dy, int button)
 {
-  static unsigned int info_delay = 0;
+  static DelayCounter info_delay = { 0 };
   static int num_anims;
   static int num_pages;
   static int page;
   int anims_per_page = NUM_INFO_ELEMENTS_ON_SCREEN;
   int i;
 
+  info_delay.value = GameFrameDelay;
+
   if (button == MB_MENU_INITIALIZE)
   {
     boolean new_element = TRUE;
@@ -3122,18 +3528,18 @@ void HandleInfoScreen_Elements(int button)
 
     return;
   }
-  else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
+  else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE || dx)
   {
     if (button != MB_MENU_INITIALIZE)
     {
       PlaySound(SND_MENU_ITEM_SELECTING);
 
-      page++;
+      page += (dx < 0 ? -1 : +1);
     }
 
-    if (page >= num_pages)
+    if (page < 0 || page >= num_pages)
     {
-      FadeMenuSoundsAndMusic();
+      FadeInfoSoundsAndMusic();
 
       info_mode = INFO_MODE_MAIN;
       DrawInfoScreen();
@@ -3141,12 +3547,15 @@ void HandleInfoScreen_Elements(int button)
       return;
     }
 
-    if (page > 0)
+    if (button != MB_MENU_INITIALIZE)
       FadeSetNextScreen();
 
     if (button != MB_MENU_INITIALIZE)
       FadeOut(REDRAW_FIELD);
 
+    ClearField();
+
+    DrawInfoScreen_Headline(page, num_pages, TRUE);
     DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
 
     if (button != MB_MENU_INITIALIZE)
@@ -3154,11 +3563,11 @@ void HandleInfoScreen_Elements(int button)
   }
   else
   {
-    if (DelayReached(&info_delay, GameFrameDelay))
+    if (DelayReached(&info_delay))
       if (page < num_pages)
        DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
 
-    PlayMenuSoundIfLoop();
+    PlayInfoSoundIfLoop();
   }
 }
 
@@ -3166,34 +3575,48 @@ static void DrawInfoScreen_Music(void)
 {
   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
 
+  UnmapAllGadgets();
+
   FadeOut(REDRAW_FIELD);
 
   ClearField();
-  DrawHeadline();
+
+  DrawInfoScreen_Headline(0, 1, TRUE);
 
   LoadMusicInfo();
 
-  HandleInfoScreen_Music(MB_MENU_INITIALIZE);
+  HandleInfoScreen_Music(0, 0, MB_MENU_INITIALIZE);
 
   FadeIn(REDRAW_FIELD);
 }
 
-void HandleInfoScreen_Music(int button)
+void HandleInfoScreen_Music(int dx, int dy, int button)
 {
   static struct MusicFileInfo *list = NULL;
+  static int num_screens = 0;
+  static int screen_nr = 0;
   int font_title = MENU_INFO_FONT_TITLE;
   int font_head  = MENU_INFO_FONT_HEAD;
   int font_text  = MENU_INFO_FONT_TEXT;
   int font_foot  = MENU_INFO_FONT_FOOT;
-  int spacing_title = menu.headline1_spacing_info[info_mode];
-  int spacing_head  = menu.headline2_spacing_info[info_mode];
-  int ystep_title = getMenuTextStep(spacing_title, font_title);
-  int ystep_head  = getMenuTextStep(spacing_head,  font_head);
-  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART1;
+  int spacing_head = menu.headline2_spacing_info[info_mode];
+  int ystep_head = getMenuTextStep(spacing_head,  font_head);
+  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART;
   int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
 
   if (button == MB_MENU_INITIALIZE)
   {
+    struct MusicFileInfo *list_ptr = music_file_info;
+
+    num_screens = 0;
+    screen_nr = 0;
+
+    while (list_ptr != NULL)
+    {
+      list_ptr = list_ptr->next;
+      num_screens++;
+    }
+
     list = music_file_info;
 
     if (list == NULL)
@@ -3201,13 +3624,11 @@ void HandleInfoScreen_Music(int button)
       FadeMenuSoundsAndMusic();
 
       ClearField();
-      DrawHeadline();
 
-      DrawTextSCentered(ystart, font_title,
-                       "No music info for this level set.");
+      DrawInfoScreen_Headline(0, 1, TRUE);
 
-      DrawTextSCentered(ybottom, font_foot,
-                       "Press any key or button for info menu");
+      DrawTextSCentered(ystart, font_title, "No music info for this level set.");
+      DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_MENU);
 
       return;
     }
@@ -3224,14 +3645,17 @@ void HandleInfoScreen_Music(int button)
 
     return;
   }
-  else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
+  else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE || dx)
   {
     if (button != MB_MENU_INITIALIZE)
     {
       PlaySound(SND_MENU_ITEM_SELECTING);
 
       if (list != NULL)
-       list = list->next;
+      {
+       list = (dx < 0 ? list->prev : list->next);
+       screen_nr += (dx < 0 ? -1 : +1);
+      }
     }
 
     if (list == NULL)
@@ -3253,40 +3677,36 @@ void HandleInfoScreen_Music(int button)
       FadeOut(REDRAW_FIELD);
 
     ClearField();
-    DrawHeadline();
+
+    DrawInfoScreen_Headline(screen_nr, num_screens, TRUE);
 
     if (list->is_sound)
     {
       int sound = list->music;
 
-      if (sound_info[sound].loop)
+      if (IS_LOOP_SOUND(sound))
        PlaySoundLoop(sound);
       else
        PlaySound(sound);
-
-      DrawTextSCentered(ystart, font_title, "The Game Background Sounds:");
     }
     else
     {
       int music = list->music;
 
-      if (music_info[music].loop)
+      if (IS_LOOP_MUSIC(music))
        PlayMusicLoop(music);
       else
        PlayMusic(music);
-
-      DrawTextSCentered(ystart, font_title, "The Game Background Music:");
     }
 
-    ystart += ystep_title;
-
     if (!strEqual(list->title, UNKNOWN_NAME))
     {
       if (!strEqual(list->title_header, UNKNOWN_NAME))
-      {
        DrawTextSCentered(ystart, font_head, list->title_header);
-       ystart += ystep_head;
-      }
+      else
+       DrawTextSCentered(ystart, font_head, "Track");
+
+      ystart += ystep_head;
 
       DrawTextFCentered(ystart, font_text, "\"%s\"", list->title);
       ystart += ystep_head;
@@ -3331,419 +3751,74 @@ void HandleInfoScreen_Music(int button)
       ystart += ystep_head;
     }
 
-    DrawTextSCentered(ybottom, FONT_TEXT_4,
-                     "Press any key or button for next page");
+    if (!strEqual(list->played, UNKNOWN_NAME))
+    {
+      if (!strEqual(list->played_header, UNKNOWN_NAME))
+       DrawTextSCentered(ystart, font_head, list->played_header);
+      else
+       DrawTextSCentered(ystart, font_head, "played in");
 
-    if (button != MB_MENU_INITIALIZE)
-      FadeIn(REDRAW_FIELD);
-  }
+      ystart += ystep_head;
 
-  if (list != NULL && list->is_sound && sound_info[list->music].loop)
-    PlaySoundLoop(list->music);
-}
+      DrawTextFCentered(ystart, font_text, "%s", list->played);
+      ystart += ystep_head;
+    }
+    else if (!list->is_sound)
+    {
+      int music_level_nr = -1;
+      int i;
 
-static void DrawInfoScreen_CreditsScreen(int screen_nr)
-{
-  int font_title = MENU_INFO_FONT_TITLE;
-  int font_head  = MENU_INFO_FONT_HEAD;
-  int font_text  = MENU_INFO_FONT_TEXT;
-  int font_foot  = MENU_INFO_FONT_FOOT;
-  int spacing_title = menu.headline1_spacing_info[info_mode];
-  int spacing_head  = menu.headline2_spacing_info[info_mode];
-  int spacing_para  = menu.paragraph_spacing_info[info_mode];
-  int spacing_line  = menu.line_spacing_info[info_mode];
-  int ystep_title = getMenuTextStep(spacing_title, font_title);
-  int ystep_head  = getMenuTextStep(spacing_head,  font_head);
-  int ystep_para  = getMenuTextStep(spacing_para,  font_text);
-  int ystep_line  = getMenuTextStep(spacing_line,  font_text);
-  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART1;
-  int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
+      // check if this music is configured for a certain level
+      for (i = leveldir_current->first_level;
+          i <= leveldir_current->last_level; i++)
+      {
+       // (special case: "list->music" may be negative for unconfigured music)
+       if (levelset.music[i] != MUS_UNDEFINED &&
+           levelset.music[i] == list->music)
+       {
+         music_level_nr = i;
 
-  ClearField();
-  DrawHeadline();
-
-  DrawTextSCentered(ystart, font_title, "Credits:");
-  ystart += ystep_title;
-
-  if (screen_nr == 0)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Special thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Peter Liepa");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for creating");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "\"Boulder Dash\"");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "in the year");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "1984");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "published by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "First Star Software");
-  }
-  else if (screen_nr == 1)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Special thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Klaus Heinz & Volker Wertich");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for creating");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "\"Emerald Mine\"");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "in the year");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "1987");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "published by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Kingsoft");
-  }
-  else if (screen_nr == 2)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Special thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Michael Stopp & Philip Jespersen");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for creating");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "\"Supaplex\"");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "in the year");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "1991");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "published by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Digital Integration");
-  }
-  else if (screen_nr == 3)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Special thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Hiroyuki Imabayashi");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for creating");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "\"Sokoban\"");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "in the year");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "1982");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "published by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Thinking Rabbit");
-  }
-  else if (screen_nr == 4)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Special thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Alan Bond");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "and");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "J\xfcrgen Bonhagen");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for the continuous creation");
-    ystart += ystep_line;
-    DrawTextSCentered(ystart, font_head,
-                     "of outstanding level sets");
-  }
-  else if (screen_nr == 5)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Peter Elzner");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for ideas and inspiration by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Diamond Caves");
-    ystart += ystep_para;
-
-    DrawTextSCentered(ystart, font_head,
-                     "Thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Steffest");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for ideas and inspiration by");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "DX-Boulderdash");
-  }
-  else if (screen_nr == 6)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "David Tritscher");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for the code base used for the");
-    ystart += ystep_line;
-    DrawTextSCentered(ystart, font_head,
-                     "native Emerald Mine engine");
-  }
-  else if (screen_nr == 7)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "Thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Guido Schulz");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for the initial DOS port");
-    ystart += ystep_para;
-
-    DrawTextSCentered(ystart, font_head,
-                     "Thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "Karl H\xf6rnell");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "for some additional toons");
-  }
-  else if (screen_nr == 8)
-  {
-    DrawTextSCentered(ystart, font_head,
-                     "And not to forget:");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_head,
-                     "Many thanks to");
-    ystart += ystep_head;
-    DrawTextSCentered(ystart, font_text,
-                     "All those who contributed");
-    ystart += ystep_line;
-    DrawTextSCentered(ystart, font_text,
-                     "levels to this game");
-    ystart += ystep_line;
-    DrawTextSCentered(ystart, font_text,
-                     "since 1995");
-  }
+         break;
+       }
+      }
 
-  DrawTextSCentered(ybottom, font_foot,
-                   "Press any key or button for next page");
-}
+      if (music_level_nr != -1)
+      {
+       if (!strEqual(list->played_header, UNKNOWN_NAME))
+         DrawTextSCentered(ystart, font_head, list->played_header);
+       else
+         DrawTextSCentered(ystart, font_head, "played in");
 
-static void DrawInfoScreen_Credits(void)
-{
-  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
+       ystart += ystep_head;
 
-  FadeMenuSoundsAndMusic();
+       DrawTextFCentered(ystart, font_text, "level %03d", music_level_nr);
+       ystart += ystep_head;
+      }
+    }
 
-  FadeOut(REDRAW_FIELD);
+    DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_PAGE);
 
-  HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
+    if (button != MB_MENU_INITIALIZE)
+      FadeIn(REDRAW_FIELD);
+  }
 
-  FadeIn(REDRAW_FIELD);
+  if (list != NULL && list->is_sound && IS_LOOP_SOUND(list->music))
+    PlaySoundLoop(list->music);
 }
 
-void HandleInfoScreen_Credits(int button)
+static void DrawInfoScreen_Version(void)
 {
-  static int screen_nr = 0;
-  int num_screens = 9;
-
-  if (button == MB_MENU_INITIALIZE)
-  {
-    screen_nr = 0;
-
-    // DrawInfoScreen_CreditsScreen(screen_nr);
-  }
-
-  if (button == MB_MENU_LEAVE)
-  {
-    PlaySound(SND_MENU_ITEM_SELECTING);
-
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
-
-    return;
-  }
-  else if (button == MB_MENU_CHOICE || button == MB_MENU_INITIALIZE)
-  {
-    if (button != MB_MENU_INITIALIZE)
-    {
-      PlaySound(SND_MENU_ITEM_SELECTING);
-
-      screen_nr++;
-    }
-
-    if (screen_nr >= num_screens)
-    {
-      FadeMenuSoundsAndMusic();
-
-      info_mode = INFO_MODE_MAIN;
-      DrawInfoScreen();
-
-      return;
-    }
-
-    if (screen_nr > 0)
-      FadeSetNextScreen();
-
-    if (button != MB_MENU_INITIALIZE)
-      FadeOut(REDRAW_FIELD);
-
-    DrawInfoScreen_CreditsScreen(screen_nr);
-
-    if (button != MB_MENU_INITIALIZE)
-      FadeIn(REDRAW_FIELD);
-  }
-  else
-  {
-    PlayMenuSoundIfLoop();
-  }
-}
-
-static void DrawInfoScreen_Program(void)
-{
-  int font_title = MENU_INFO_FONT_TITLE;
-  int font_head  = MENU_INFO_FONT_HEAD;
-  int font_text  = MENU_INFO_FONT_TEXT;
-  int font_foot  = MENU_INFO_FONT_FOOT;
-  int spacing_title = menu.headline1_spacing_info[info_mode];
-  int spacing_head  = menu.headline2_spacing_info[info_mode];
-  int spacing_para  = menu.paragraph_spacing_info[info_mode];
-  int spacing_line  = menu.line_spacing_info[info_mode];
-  int ystep_title = getMenuTextStep(spacing_title, font_title);
-  int ystep_head  = getMenuTextStep(spacing_head,  font_head);
-  int ystep_para  = getMenuTextStep(spacing_para,  font_text);
-  int ystep_line  = getMenuTextStep(spacing_line,  font_text);
-  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART1;
-  int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
-
-  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
-
-  FadeOut(REDRAW_FIELD);
-
-  ClearField();
-  DrawHeadline();
-
-  DrawTextSCentered(ystart, font_title, "Program Information:");
-  ystart += ystep_title;
-
-  DrawTextSCentered(ystart, font_head,
-                   "This game is Freeware!");
-  ystart += ystep_head;
-  DrawTextSCentered(ystart, font_head,
-                   "If you like it, send e-mail to:");
-  ystart += ystep_head;
-  DrawTextSCentered(ystart, font_text,
-                   setup.internal.program_email);
-  ystart += ystep_para;
-
-  DrawTextSCentered(ystart, font_head,
-                   "More information and levels:");
-  ystart += ystep_head;
-  DrawTextSCentered(ystart, font_text,
-                   setup.internal.program_website);
-  ystart += ystep_para;
-
-  DrawTextSCentered(ystart, font_head,
-                   "If you have created new levels,");
-  ystart += ystep_line;
-  DrawTextSCentered(ystart, font_head,
-                   "send them to me to include them!");
-  ystart += ystep_head;
-  DrawTextSCentered(ystart, font_head,
-                   ":-)");
-
-  DrawTextSCentered(ybottom, font_foot,
-                   "Press any key or button for info menu");
-
-  FadeIn(REDRAW_FIELD);
-}
-
-void HandleInfoScreen_Program(int button)
-{
-  if (button == MB_MENU_LEAVE)
-  {
-    PlaySound(SND_MENU_ITEM_SELECTING);
-
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
-
-    return;
-  }
-  else if (button == MB_MENU_CHOICE)
-  {
-    PlaySound(SND_MENU_ITEM_SELECTING);
-
-    FadeMenuSoundsAndMusic();
-
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
-  }
-  else
-  {
-    PlayMenuSoundIfLoop();
-  }
-}
-
-static void DrawInfoScreen_Version(void)
-{
-  int font_title = MENU_INFO_FONT_TITLE;
-  int font_head  = MENU_INFO_FONT_HEAD;
-  int font_text  = MENU_INFO_FONT_TEXT;
-  int font_foot  = MENU_INFO_FONT_FOOT;
-  int spacing_title = menu.headline1_spacing_info[info_mode];
-  int spacing_head  = menu.headline2_spacing_info[info_mode];
-  int spacing_para  = menu.paragraph_spacing_info[info_mode];
-  int spacing_line  = menu.line_spacing_info[info_mode];
+  int font_head = MENU_INFO_FONT_HEAD;
+  int font_text = MENU_INFO_FONT_TEXT;
+  int font_foot = MENU_INFO_FONT_FOOT;
+  int spacing_head = menu.headline2_spacing_info[info_mode];
+  int spacing_para = menu.paragraph_spacing_info[info_mode];
+  int spacing_line = menu.line_spacing_info[info_mode];
   int xstep = getFontWidth(font_text);
-  int ystep_title = getMenuTextStep(spacing_title, font_title);
-  int ystep_head  = getMenuTextStep(spacing_head,  font_head);
-  int ystep_para  = getMenuTextStep(spacing_para,  font_text);
-  int ystep_line  = getMenuTextStep(spacing_line,  font_text);
-  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART1;
+  int ystep_head = getMenuTextStep(spacing_head,  font_head);
+  int ystep_para = getMenuTextStep(spacing_para,  font_text);
+  int ystep_line = getMenuTextStep(spacing_line,  font_text);
+  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
   int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
   int xstart1 = mSX - SX + 2 * xstep;
   int xstart2 = mSX - SX + 18 * xstep;
@@ -3756,13 +3831,14 @@ static void DrawInfoScreen_Version(void)
 
   SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_VERSION);
 
+  UnmapAllGadgets();
+  FadeInfoSoundsAndMusic();
+
   FadeOut(REDRAW_FIELD);
 
   ClearField();
-  DrawHeadline();
 
-  DrawTextSCentered(ystart, font_title, "Version Information:");
-  ystart += ystep_title;
+  DrawInfoScreen_Headline(0, 1, TRUE);
 
   DrawTextF(xstart1, ystart, font_head, "Name");
   DrawTextF(xstart2, ystart, font_text, getProgramTitleString());
@@ -3893,8 +3969,9 @@ static void DrawInfoScreen_Version(void)
   DrawTextF(xstart2, ystart, font_text, "%s", setup.system.sdl_audiodriver);
   DrawTextF(xstart3, ystart, font_text, "%s", driver_name);
 
-  DrawTextSCentered(ybottom, font_foot,
-                   "Press any key or button for info menu");
+  DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_MENU);
+
+  PlayInfoSoundsAndMusic();
 
   FadeIn(REDRAW_FIELD);
 }
@@ -3925,329 +4002,331 @@ void HandleInfoScreen_Version(int button)
   }
 }
 
-static void DrawInfoScreen_LevelSet(void)
+static char *getInfoScreenTitle_Generic(void)
 {
-  struct TitleMessageInfo *tmi = &readme;
-  char *filename = getLevelSetInfoFilename();
-  char *title = "Level Set Information:";
-  int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART1;
-  int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
+  return (info_mode == INFO_MODE_MAIN     ? STR_INFO_MAIN     :
+         info_mode == INFO_MODE_TITLE    ? STR_INFO_TITLE    :
+         info_mode == INFO_MODE_ELEMENTS ? STR_INFO_ELEMENTS :
+         info_mode == INFO_MODE_MUSIC    ? STR_INFO_MUSIC    :
+         info_mode == INFO_MODE_CREDITS  ? STR_INFO_CREDITS  :
+         info_mode == INFO_MODE_PROGRAM  ? STR_INFO_PROGRAM  :
+         info_mode == INFO_MODE_VERSION  ? STR_INFO_VERSION  :
+         info_mode == INFO_MODE_LEVELSET ? STR_INFO_LEVELSET :
+         "");
+}
 
-  if (filename == NULL)
-  {
-    DrawInfoScreen_NotAvailable(title, "No information for this level set.");
+static int getInfoScreenBackgroundImage_Generic(void)
+{
+  return (info_mode == INFO_MODE_ELEMENTS ? IMG_BACKGROUND_INFO_ELEMENTS :
+         info_mode == INFO_MODE_MUSIC    ? IMG_BACKGROUND_INFO_MUSIC    :
+         info_mode == INFO_MODE_CREDITS  ? IMG_BACKGROUND_INFO_CREDITS  :
+         info_mode == INFO_MODE_PROGRAM  ? IMG_BACKGROUND_INFO_PROGRAM  :
+         info_mode == INFO_MODE_VERSION  ? IMG_BACKGROUND_INFO_VERSION  :
+         info_mode == INFO_MODE_LEVELSET ? IMG_BACKGROUND_INFO_LEVELSET :
+         IMG_BACKGROUND_INFO);
+}
 
-    return;
-  }
+static int getInfoScreenBackgroundSound_Generic(void)
+{
+  return (info_mode == INFO_MODE_ELEMENTS ? SND_BACKGROUND_INFO_ELEMENTS :
+         info_mode == INFO_MODE_CREDITS  ? SND_BACKGROUND_INFO_CREDITS  :
+         info_mode == INFO_MODE_PROGRAM  ? SND_BACKGROUND_INFO_PROGRAM  :
+         info_mode == INFO_MODE_VERSION  ? SND_BACKGROUND_INFO_VERSION  :
+         info_mode == INFO_MODE_LEVELSET ? SND_BACKGROUND_INFO_LEVELSET :
+         SND_BACKGROUND_INFO);
+}
 
-  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
+static int getInfoScreenBackgroundMusic_Generic(void)
+{
+  return (info_mode == INFO_MODE_ELEMENTS ? MUS_BACKGROUND_INFO_ELEMENTS :
+         info_mode == INFO_MODE_CREDITS  ? MUS_BACKGROUND_INFO_CREDITS  :
+         info_mode == INFO_MODE_PROGRAM  ? MUS_BACKGROUND_INFO_PROGRAM  :
+         info_mode == INFO_MODE_VERSION  ? MUS_BACKGROUND_INFO_VERSION  :
+         info_mode == INFO_MODE_LEVELSET ? MUS_BACKGROUND_INFO_LEVELSET :
+         MUS_BACKGROUND_INFO);
+}
 
-  FadeOut(REDRAW_FIELD);
+static char *getInfoScreenFilename_Generic(int nr, boolean global)
+{
+  return (info_mode == INFO_MODE_CREDITS  ? getCreditsFilename(nr, global) :
+         info_mode == INFO_MODE_PROGRAM  ? getProgramInfoFilename(nr)     :
+         info_mode == INFO_MODE_LEVELSET ? getLevelSetInfoFilename(nr)    :
+         NULL);
+}
+
+static void DrawInfoScreen_GenericScreen(int screen_nr, int num_screens,
+                                        int use_global_screens)
+{
+  char *filename = getInfoScreenFilename_Generic(screen_nr, use_global_screens);
+  int font_text = MENU_INFO_FONT_TEXT;
+  int font_foot = MENU_INFO_FONT_FOOT;
+  int spacing_line = menu.line_spacing_info[info_mode];
+  int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
 
   ClearField();
-  DrawHeadline();
 
-  DrawTextSCentered(ystart, FONT_TEXT_1, title);
+  DrawInfoScreen_Headline(screen_nr, num_screens, use_global_screens);
 
-  // if x position set to "-1", automatically determine by playfield width
-  if (tmi->x == -1)
-    tmi->x = SXSIZE / 2;
+  if (info_mode == INFO_MODE_CREDITS ||
+      info_mode == INFO_MODE_PROGRAM)
+  {
+    int width = SXSIZE;
+    int height = MENU_SCREEN_INFO_YBOTTOM - MENU_SCREEN_INFO_YSTART;
+    int chars = width / getFontWidth(font_text);
+    int lines = height / getFontHeight(font_text);
+    int padx = (width - chars * getFontWidth(font_text)) / 2;
+    int line_spacing = getMenuTextSpacing(spacing_line, font_text);
+    int xstart = mSX + padx;
+    int ystart = mSY + MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
+    boolean autowrap = FALSE;
+    boolean centered = TRUE;
+    boolean parse_comments = TRUE;
 
-  // if y position set to "-1", use static default value
-  if (tmi->y == -1)
-    tmi->y = 150;
+    DrawTextFile(xstart, ystart,
+                filename, font_text, chars, -1, lines, line_spacing, -1,
+                autowrap, centered, parse_comments);
+  }
+  else if (info_mode == INFO_MODE_LEVELSET)
+  {
+    struct TitleMessageInfo *tmi = &readme;
 
-  // if width set to "-1", automatically determine by playfield width
-  if (tmi->width == -1)
-    tmi->width = SXSIZE - 2 * TILEX;
+    // if x position set to "-1", automatically determine by playfield width
+    if (tmi->x == -1)
+      tmi->x = SXSIZE / 2;
 
-  // if height set to "-1", automatically determine by playfield height
-  if (tmi->height == -1)
-    tmi->height = MENU_SCREEN_INFO_YBOTTOM - tmi->y - 10;
+    // if y position set to "-1", use static default value
+    if (tmi->y == -1)
+      tmi->y = MENU_SCREEN_INFO_YSTART + getHeadlineSpacing();
 
-  // if chars set to "-1", automatically determine by text and font width
-  if (tmi->chars == -1)
-    tmi->chars = tmi->width / getFontWidth(tmi->font);
-  else
-    tmi->width = tmi->chars * getFontWidth(tmi->font);
+    // if width set to "-1", automatically determine by playfield width
+    if (tmi->width == -1)
+      tmi->width = SXSIZE - 2 * TILEX;
 
-  // if lines set to "-1", automatically determine by text and font height
-  if (tmi->lines == -1)
-    tmi->lines = tmi->height / getFontHeight(tmi->font);
-  else
-    tmi->height = tmi->lines * getFontHeight(tmi->font);
+    // if height set to "-1", automatically determine by playfield height
+    if (tmi->height == -1)
+      tmi->height = MENU_SCREEN_INFO_YBOTTOM - tmi->y - 10;
 
-  DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
-              filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
-              tmi->autowrap, tmi->centered, tmi->parse_comments);
+    // if chars set to "-1", automatically determine by text and font width
+    if (tmi->chars == -1)
+      tmi->chars = tmi->width / getFontWidth(tmi->font);
+    else
+      tmi->width = tmi->chars * getFontWidth(tmi->font);
 
-  DrawTextSCentered(ybottom, FONT_TEXT_4,
-                   "Press any key or button for info menu");
+    // if lines set to "-1", automatically determine by text and font height
+    if (tmi->lines == -1)
+      tmi->lines = tmi->height / getFontHeight(tmi->font);
+    else
+      tmi->height = tmi->lines * getFontHeight(tmi->font);
 
-  FadeIn(REDRAW_FIELD);
+    DrawTextFile(mSX + ALIGNED_TEXT_XPOS(tmi), mSY + ALIGNED_TEXT_YPOS(tmi),
+                filename, tmi->font, tmi->chars, -1, tmi->lines, 0, -1,
+                tmi->autowrap, tmi->centered, tmi->parse_comments);
+  }
+
+  boolean last_screen = (screen_nr == num_screens - 1);
+  char *text_foot = (last_screen ? TEXT_NEXT_MENU : TEXT_NEXT_PAGE);
+
+  DrawTextSCentered(ybottom, font_foot, text_foot);
 }
 
-static void HandleInfoScreen_LevelSet(int button)
+static void DrawInfoScreen_Generic(void)
 {
-  if (button == MB_MENU_LEAVE)
-  {
-    PlaySound(SND_MENU_ITEM_SELECTING);
+  SetMainBackgroundImageIfDefined(getInfoScreenBackgroundImage_Generic());
 
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
+  UnmapAllGadgets();
+  FadeInfoSoundsAndMusic();
 
-    return;
-  }
-  else if (button == MB_MENU_CHOICE)
-  {
-    PlaySound(SND_MENU_ITEM_SELECTING);
+  FadeOut(REDRAW_FIELD);
 
-    FadeMenuSoundsAndMusic();
+  HandleInfoScreen_Generic(0, 0, MB_MENU_INITIALIZE);
 
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
-  }
-  else
-  {
-    PlayMenuSoundIfLoop();
-  }
+  PlayInfoSoundsAndMusic();
+
+  FadeIn(REDRAW_FIELD);
 }
 
-static void DrawInfoScreen(void)
+void HandleInfoScreen_Generic(int dx, int dy, int button)
 {
-  if (info_mode == INFO_MODE_TITLE)
-    DrawInfoScreen_TitleScreen();
-  else if (info_mode == INFO_MODE_ELEMENTS)
-    DrawInfoScreen_Elements();
-  else if (info_mode == INFO_MODE_MUSIC)
-    DrawInfoScreen_Music();
-  else if (info_mode == INFO_MODE_CREDITS)
-    DrawInfoScreen_Credits();
-  else if (info_mode == INFO_MODE_PROGRAM)
-    DrawInfoScreen_Program();
-  else if (info_mode == INFO_MODE_VERSION)
-    DrawInfoScreen_Version();
-  else if (info_mode == INFO_MODE_LEVELSET)
-    DrawInfoScreen_LevelSet();
-  else
-    DrawInfoScreen_Main();
+  static char *text_no_info = "";
+  static int num_screens = 0;
+  static int screen_nr = 0;
+  static boolean use_global_screens = FALSE;
 
-  if (info_mode != INFO_MODE_MAIN &&
-      info_mode != INFO_MODE_TITLE &&
-      info_mode != INFO_MODE_MUSIC)
-    PlayMenuSoundsAndMusic();
-}
+  if (button == MB_MENU_INITIALIZE)
+  {
+    num_screens = 0;
+    screen_nr = 0;
 
-void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
-{
-  if (info_mode == INFO_MODE_TITLE)
-    HandleInfoScreen_TitleScreen(button);
-  else if (info_mode == INFO_MODE_ELEMENTS)
-    HandleInfoScreen_Elements(button);
-  else if (info_mode == INFO_MODE_MUSIC)
-    HandleInfoScreen_Music(button);
-  else if (info_mode == INFO_MODE_CREDITS)
-    HandleInfoScreen_Credits(button);
-  else if (info_mode == INFO_MODE_PROGRAM)
-    HandleInfoScreen_Program(button);
-  else if (info_mode == INFO_MODE_VERSION)
-    HandleInfoScreen_Version(button);
-  else if (info_mode == INFO_MODE_LEVELSET)
-    HandleInfoScreen_LevelSet(button);
-  else
-    HandleInfoScreen_Main(mx, my, dx, dy, button);
-}
+    if (info_mode == INFO_MODE_CREDITS)
+    {
+      int i;
 
+      for (i = 0; i < 2; i++)
+      {
+       use_global_screens = i;         // check for "FALSE", then "TRUE"
 
-// ============================================================================
-// change name functions
-// ============================================================================
+       // determine number of (global or level set specific) credits screens
+       while (getCreditsFilename(num_screens, use_global_screens) != NULL)
+         num_screens++;
 
-struct ApiRenamePlayerThreadData
-{
-  char *player_name;
-  char *player_uuid;
-};
+       if (num_screens > 0)
+         break;
+      }
 
-static void *CreateThreadData_ApiRenamePlayer(void)
-{
-  struct ApiRenamePlayerThreadData *data =
-    checked_malloc(sizeof(struct ApiRenamePlayerThreadData));
+      text_no_info = "No credits available.";
+    }
+    else if (info_mode == INFO_MODE_PROGRAM)
+    {
+      use_global_screens = TRUE;
 
-  data->player_name = getStringCopy(setup.player_name);
-  data->player_uuid = getStringCopy(setup.player_uuid);
+      // determine number of program info screens
+      while (getProgramInfoFilename(num_screens) != NULL)
+       num_screens++;
 
-  return data;
-}
+      text_no_info = "No program info available.";
+    }
+    else if (info_mode == INFO_MODE_LEVELSET)
+    {
+      use_global_screens = FALSE;
 
-static void FreeThreadData_ApiRenamePlayer(void *data_raw)
-{
-  struct ApiRenamePlayerThreadData *data = data_raw;
+      // determine number of levelset info screens
+      while (getLevelSetInfoFilename(num_screens) != NULL)
+       num_screens++;
 
-  checked_free(data->player_name);
-  checked_free(data->player_uuid);
-  checked_free(data);
-}
+      text_no_info = "No level set info available.";
+    }
 
-static boolean SetRequest_ApiRenamePlayer(struct HttpRequest *request,
-                                         void *data_raw)
-{
-  struct ApiRenamePlayerThreadData *data = data_raw;
-  char *player_name_raw = data->player_name;
-  char *player_uuid_raw = data->player_uuid;
+    if (num_screens == 0)
+    {
+      int font_title = MENU_INFO_FONT_TITLE;
+      int font_foot  = MENU_INFO_FONT_FOOT;
+      int ystart  = mSY - SY + MENU_SCREEN_INFO_YSTART;
+      int ybottom = mSY - SY + MENU_SCREEN_INFO_YBOTTOM;
 
-  request->hostname = setup.api_server_hostname;
-  request->port     = API_SERVER_PORT;
-  request->method   = API_SERVER_METHOD;
-  request->uri      = API_SERVER_URI_RENAME;
+      ClearField();
 
-  char *player_name = getEscapedJSON(player_name_raw);
-  char *player_uuid = getEscapedJSON(player_uuid_raw);
+      DrawInfoScreen_Headline(screen_nr, num_screens, use_global_screens);
 
-  snprintf(request->body, MAX_HTTP_BODY_SIZE,
-          "{\n"
-          "%s"
-          "  \"game_version\":         \"%s\",\n"
-          "  \"game_platform\":        \"%s\",\n"
-          "  \"name\":                 \"%s\",\n"
-          "  \"uuid\":                 \"%s\"\n"
-          "}\n",
-          getPasswordJSON(setup.api_server_password),
-          getProgramRealVersionString(),
-          getProgramPlatformString(),
-          player_name,
-          player_uuid);
+      DrawTextSCentered(ystart, font_title, text_no_info);
+      DrawTextSCentered(ybottom, font_foot, TEXT_NEXT_MENU);
 
-  checked_free(player_name);
-  checked_free(player_uuid);
+      return;
+    }
 
-  ConvertHttpRequestBodyToServerEncoding(request);
+    DrawInfoScreen_GenericScreen(screen_nr, num_screens, use_global_screens);
+  }
+  else if (button == MB_MENU_LEAVE)
+  {
+    PlaySound(SND_MENU_ITEM_SELECTING);
 
-  return TRUE;
-}
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+  }
+  else if (button == MB_MENU_CHOICE || dx)
+  {
+    PlaySound(SND_MENU_ITEM_SELECTING);
 
-static void HandleResponse_ApiRenamePlayer(struct HttpResponse *response,
-                                          void *data_raw)
-{
-  // nothing to do here
-}
+    screen_nr += (dx < 0 ? -1 : +1);
 
-#if defined(PLATFORM_EMSCRIPTEN)
-static void Emscripten_ApiRenamePlayer_Loaded(unsigned handle, void *data_raw,
-                                             void *buffer, unsigned int size)
-{
-  struct HttpResponse *response = GetHttpResponseFromBuffer(buffer, size);
+    if (screen_nr < 0 || screen_nr >= num_screens)
+    {
+      FadeInfoSoundsAndMusic();
 
-  if (response != NULL)
-  {
-    HandleResponse_ApiRenamePlayer(response, data_raw);
+      info_mode = INFO_MODE_MAIN;
+      DrawInfoScreen();
+    }
+    else
+    {
+      FadeSetNextScreen();
+
+      FadeOut(REDRAW_FIELD);
+
+      DrawInfoScreen_GenericScreen(screen_nr, num_screens, use_global_screens);
 
-    checked_free(response);
+      FadeIn(REDRAW_FIELD);
+    }
   }
   else
   {
-    Error("server response too large to handle (%d bytes)", size);
+    PlayInfoSoundIfLoop();
   }
-
-  FreeThreadData_ApiRenamePlayer(data_raw);
 }
 
-static void Emscripten_ApiRenamePlayer_Failed(unsigned handle, void *data_raw,
-                                             int code, const char *status)
-{
-  Error("server failed to handle request: %d %s", code, status);
-
-  FreeThreadData_ApiRenamePlayer(data_raw);
-}
-
-static void Emscripten_ApiRenamePlayer_Progress(unsigned handle, void *data_raw,
-                                               int bytes, int size)
+static void DrawInfoScreen(void)
 {
-  // nothing to do here
+  if (info_mode == INFO_MODE_TITLE)
+    DrawInfoScreen_TitleScreen();
+  else if (info_mode == INFO_MODE_ELEMENTS)
+    DrawInfoScreen_Elements();
+  else if (info_mode == INFO_MODE_MUSIC)
+    DrawInfoScreen_Music();
+  else if (info_mode == INFO_MODE_CREDITS)
+    DrawInfoScreen_Generic();
+  else if (info_mode == INFO_MODE_PROGRAM)
+    DrawInfoScreen_Generic();
+  else if (info_mode == INFO_MODE_VERSION)
+    DrawInfoScreen_Version();
+  else if (info_mode == INFO_MODE_LEVELSET)
+    DrawInfoScreen_Generic();
+  else
+    DrawInfoScreen_Main();
 }
 
-static void Emscripten_ApiRenamePlayer_HttpRequest(struct HttpRequest *request,
-                                                  void *data_raw)
+void DrawInfoScreen_FromMainMenu(int nr)
 {
-  if (!SetRequest_ApiRenamePlayer(request, data_raw))
-  {
-    FreeThreadData_ApiRenamePlayer(data_raw);
+  int fade_mask = REDRAW_FIELD;
 
+  if (nr < INFO_MODE_MAIN || nr >= MAX_INFO_MODES)
     return;
-  }
 
-  emscripten_async_wget2_data(request->uri,
-                             request->method,
-                             request->body,
-                             data_raw,
-                             TRUE,
-                             Emscripten_ApiRenamePlayer_Loaded,
-                             Emscripten_ApiRenamePlayer_Failed,
-                             Emscripten_ApiRenamePlayer_Progress);
-}
+  CloseDoor(DOOR_CLOSE_2);
 
-#else
-
-static void ApiRenamePlayer_HttpRequestExt(struct HttpRequest *request,
-                                          struct HttpResponse *response,
-                                          void *data_raw)
-{
-  if (!SetRequest_ApiRenamePlayer(request, data_raw))
-    return;
+  SetGameStatus(GAME_MODE_INFO);
 
-  if (!DoHttpRequest(request, response))
-  {
-    Error("HTTP request failed: %s", GetHttpError());
+  info_mode = nr;
+  info_screens_from_main = TRUE;
 
-    return;
-  }
-
-  if (!HTTP_SUCCESS(response->status_code))
-  {
-    Error("server failed to handle request: %d %s",
-         response->status_code,
-         response->status_text);
+  if (redraw_mask & REDRAW_ALL)
+    fade_mask = REDRAW_ALL;
 
-    return;
-  }
+  if (CheckFadeAll())
+    fade_mask = REDRAW_ALL;
 
-  HandleResponse_ApiRenamePlayer(response, data_raw);
-}
+  UnmapAllGadgets();
+  FadeMenuSoundsAndMusic();
 
-static void ApiRenamePlayer_HttpRequest(struct HttpRequest *request,
-                                   struct HttpResponse *response,
-                                   void *data_raw)
-{
-  ApiRenamePlayer_HttpRequestExt(request, response, data_raw);
+  FadeSetEnterScreen();
 
-  FreeThreadData_ApiRenamePlayer(data_raw);
-}
-#endif
+  FadeOut(fade_mask);
 
-static int ApiRenamePlayerThread(void *data_raw)
-{
-  struct HttpRequest *request = checked_calloc(sizeof(struct HttpRequest));
-  struct HttpResponse *response = checked_calloc(sizeof(struct HttpResponse));
+  FadeSkipNextFadeOut();
 
-#if defined(PLATFORM_EMSCRIPTEN)
-  Emscripten_ApiRenamePlayer_HttpRequest(request, data_raw);
-#else
-  ApiRenamePlayer_HttpRequest(request, response, data_raw);
-#endif
+  // needed if different viewport properties defined for info screen
+  ChangeViewportPropertiesIfNeeded();
 
-  checked_free(request);
-  checked_free(response);
+  SetMainBackgroundImage(IMG_BACKGROUND_INFO);
 
-  return 0;
+  DrawInfoScreen();
 }
 
-static void ApiRenamePlayerAsThread(void)
+void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
 {
-  struct ApiRenamePlayerThreadData *data = CreateThreadData_ApiRenamePlayer();
-
-  ExecuteAsThread(ApiRenamePlayerThread,
-                 "ApiRenamePlayer", data,
-                 "rename player on server");
+  if (info_mode == INFO_MODE_TITLE)
+    HandleInfoScreen_TitleScreen(dx, dy, button);
+  else if (info_mode == INFO_MODE_ELEMENTS)
+    HandleInfoScreen_Elements(dx, dy, button);
+  else if (info_mode == INFO_MODE_MUSIC)
+    HandleInfoScreen_Music(dx, dy, button);
+  else if (info_mode == INFO_MODE_CREDITS)
+    HandleInfoScreen_Generic(dx, dy, button);
+  else if (info_mode == INFO_MODE_PROGRAM)
+    HandleInfoScreen_Generic(dx, dy, button);
+  else if (info_mode == INFO_MODE_VERSION)
+    HandleInfoScreen_Version(button);
+  else if (info_mode == INFO_MODE_LEVELSET)
+    HandleInfoScreen_Generic(dx, dy, button);
+  else
+    HandleInfoScreen_Main(mx, my, dx, dy, button);
 }
 
 
@@ -4265,7 +4344,7 @@ static int getPlayerNameColor(char *name)
 }
 
 static void drawTypeNameText(char *name, struct TextPosInfo *pos,
-                             boolean active)
+                            boolean active)
 {
   char text[MAX_PLAYER_NAME_LEN + 2] = { 0 };
   boolean multiple_users = (game_status == GAME_MODE_PSEUDO_TYPENAMES);
@@ -4273,8 +4352,12 @@ static void drawTypeNameText(char *name, struct TextPosInfo *pos,
   int sy = (multiple_users ? amSY + pos->y : mSY + ALIGNED_TEXT_YPOS(pos));
   int font_nr = (active ? FONT_ACTIVE(pos->font) : pos->font);
   int font_width = getFontWidth(font_nr);
+  int font_xoffset = getFontDrawOffsetX(font_nr);
+  int font_yoffset = getFontDrawOffsetY(font_nr);
+  int font_sx = sx + font_xoffset;
+  int font_sy = sy + font_yoffset;
 
-  DrawBackgroundForFont(sx, sy, pos->width, pos->height, font_nr);
+  DrawBackgroundForFont(font_sx, font_sy, pos->width, pos->height, font_nr);
 
   sprintf(text, "%s%c", name, (active ? '_' : '\0'));
 
@@ -4590,20 +4673,37 @@ static int getAlignYOffsetFromTreeInfo(TreeInfo *ti)
   return align_yoffset;
 }
 
+static void StartPlayingFromHallOfFame(void)
+{
+  level_nr = scores.next_level_nr;
+  LoadLevel(level_nr);
+
+  StartGameActions(network.enabled, setup.autorecord, level.random_seed);
+}
+
 static void DrawChooseTree(TreeInfo **ti_ptr)
 {
   int fade_mask = REDRAW_FIELD;
+  boolean restart_music = (game_status != game_status_last_screen &&
+                          game_status_last_screen != GAME_MODE_SCOREINFO);
+
+  scores.continue_on_return = (game_status == GAME_MODE_SCORES &&
+                              game_status_last_screen == GAME_MODE_PLAYING);
 
   if (CheckFadeAll())
     fade_mask = REDRAW_ALL;
 
-  if (strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY))
+  if (*ti_ptr != NULL && strEqual((*ti_ptr)->subdir, STRING_TOP_DIRECTORY))
   {
     if (game_status == GAME_MODE_SETUP)
     {
       execSetupArtwork();
     }
-    else       // GAME_MODE_LEVELS
+    else if (game_status == GAME_MODE_SCORES && scores.continue_playing)
+    {
+      StartPlayingFromHallOfFame();
+    }
+    else
     {
       SetGameStatus(GAME_MODE_MAIN);
 
@@ -4618,9 +4718,12 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
   FreeScreenGadgets();
   CreateScreenGadgets();
 
+  if (restart_music)
+    FadeMenuSoundsAndMusic();
+
   FadeOut(fade_mask);
 
-  // needed if different viewport properties defined for choosing level (set)
+  // needed if different viewport properties defined for this screen
   ChangeViewportPropertiesIfNeeded();
 
   if (game_status == GAME_MODE_NAMES)
@@ -4629,20 +4732,38 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
     SetMainBackgroundImage(IMG_BACKGROUND_LEVELNR);
   else if (game_status == GAME_MODE_LEVELS)
     SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
+  else if (game_status == GAME_MODE_SCORES)
+    SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
 
   ClearField();
 
   OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
 
+  // map gadgets for high score screen
+  if (game_status == GAME_MODE_SCORES)
+    MapScreenMenuGadgets(SCREEN_MASK_SCORES);
+
   MapScreenTreeGadgets(*ti_ptr);
+
   HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
 
   DrawMaskedBorder(fade_mask);
 
+  if (restart_music)
+    PlayMenuSoundsAndMusic();
+
   FadeIn(fade_mask);
 }
 
-static void drawChooseTreeText(int y, boolean active, TreeInfo *ti)
+static int getChooseTreeFont(TreeInfo *node, boolean active)
+{
+  if (game_status == GAME_MODE_SCORES)
+    return (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
+  else
+    return MENU_CHOOSE_TREE_FONT(MENU_CHOOSE_TREE_COLOR(node, active));
+}
+
+static void drawChooseTreeText(TreeInfo *ti, int y, boolean active)
 {
   int num_entries = numTreeInfoInGroup(ti);
   boolean scrollbar_needed = (num_entries > NUM_MENU_ENTRIES_ON_SCREEN);
@@ -4652,38 +4773,88 @@ static void drawChooseTreeText(int y, boolean active, TreeInfo *ti)
   int entry_pos = first_entry + y;
   TreeInfo *node_first = getTreeInfoFirstGroupEntry(ti);
   TreeInfo *node = getTreeInfoFromPos(node_first, entry_pos);
-  int font_color = MENU_CHOOSE_TREE_COLOR(node, active);
-  int font_nr = MENU_CHOOSE_TREE_FONT(font_color);
-  int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
+  int font_nr = getChooseTreeFont(node, active);
+  int font_xoffset = getFontDrawOffsetX(font_nr);
   int xpos = MENU_SCREEN_START_XPOS;
   int ypos = MENU_SCREEN_START_YPOS + y;
-  int startx = amSX + xpos * 32;
-  int starty = amSY + ypos * 32;
+  int startdx = xpos * 32;
+  int startdy = ypos * 32;
+  int startx = amSX + startdx;
+  int starty = amSY + startdy;
   int startx_text = startx + font_xoffset;
   int endx_text = amSX + screen_width;
   int max_text_size = endx_text - startx_text;
   int max_buffer_len = max_text_size / getFontWidth(font_nr);
   char buffer[max_buffer_len + 1];
 
-  strncpy(buffer, node->name, max_buffer_len);
-  buffer[max_buffer_len] = '\0';
+  if (game_status == GAME_MODE_SCORES && !node->parent_link)
+  {
+    int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
+    int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
+    int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
+    int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
+    int font_size_1 = getFontWidth(font_nr1);
+    int font_size_3 = getFontWidth(font_nr3);
+    int font_size_4 = getFontWidth(font_nr4);
+    int text_size_1 = 4 * font_size_1;
+    int text_size_4 = 5 * font_size_4;
+    int border = amSX - SX + getFontDrawOffsetX(font_nr1);
+    int dx1 = 0;
+    int dx3 = text_size_1;
+    int dx4 = SXSIZE - 2 * startdx - 2 * border - text_size_4;
+    int num_dots = (dx4 - dx3) / font_size_3;
+    int startx1 = startx + dx1;
+    int startx3 = startx + dx3;
+    int startx4 = startx + dx4;
+    int pos = node->pos;
+    char *pos_text = getHallOfFameRankText(pos, 3);
+    int i;
+
+    // highlight all high score entries of the current player
+    if (strEqual(scores.entry[pos].name, setup.player_name))
+      font_nr2 = FONT_TEXT_2_ACTIVE;
+
+    DrawText(startx1, starty, pos_text, font_nr1);
 
-  DrawText(startx, starty, buffer, font_nr);
+    for (i = 0; i < num_dots; i++)
+      DrawText(startx3 + i * font_size_3, starty, ".", font_nr3);
+
+    if (!strEqual(scores.entry[pos].name, EMPTY_PLAYER_NAME))
+      DrawText(startx3, starty, scores.entry[pos].name, font_nr2);
+
+    DrawText(startx4, starty, getHallOfFameScoreText(pos, 5), font_nr4);
+  }
+  else
+  {
+    strncpy(buffer, node->name, max_buffer_len);
+    buffer[max_buffer_len] = '\0';
+
+    DrawText(startx, starty, buffer, font_nr);
+  }
 }
 
-static void drawChooseTreeList(int first_entry, int num_page_entries,
-                              TreeInfo *ti)
+static void drawChooseTreeHeadExt(int type, char *title_string)
 {
-  int i;
-  char *title_string = NULL;
   int yoffset_sets = MENU_TITLE1_YPOS;
   int yoffset_setup = 16;
-  int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ||
-                ti->type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup);
-
-  title_string = ti->infotext;
+  int yoffset = (type == TREE_TYPE_SCORE_ENTRY ||
+                type == TREE_TYPE_LEVEL_DIR ||
+                type == TREE_TYPE_LEVEL_NR ? yoffset_sets : yoffset_setup);
 
   DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
+}
+
+static void drawChooseTreeHead(TreeInfo *ti)
+{
+  drawChooseTreeHeadExt(ti->type, ti->infotext);
+}
+
+static void drawChooseTreeList(TreeInfo *ti)
+{
+  int first_entry = ti->cl_first;
+  int num_entries = numTreeInfoInGroup(ti);
+  int num_page_entries = MIN(num_entries, NUM_MENU_ENTRIES_ON_SCREEN);
+  int i;
 
   clearMenuListArea();
 
@@ -4695,7 +4866,7 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
     node_first = getTreeInfoFirstGroupEntry(ti);
     node = getTreeInfoFromPos(node_first, entry_pos);
 
-    drawChooseTreeText(i, FALSE, ti);
+    drawChooseTreeText(ti, i, FALSE);
 
     if (node->parent_link)
       initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
@@ -4704,6 +4875,9 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
     else
       initCursor(i, IMG_MENU_BUTTON);
 
+    if (game_status == GAME_MODE_SCORES && node->pos == scores.last_added)
+      initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
+
     if (game_status == GAME_MODE_NAMES)
       drawChooseTreeEdit(i, FALSE);
   }
@@ -4711,21 +4885,26 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
   redraw_mask |= REDRAW_FIELD;
 }
 
-static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
+static void drawChooseTreeInfo(TreeInfo *ti)
 {
-  TreeInfo *node, *node_first;
-  int x, last_redraw_mask = redraw_mask;
+  int entry_pos = ti->cl_first + ti->cl_cursor;
+  int last_redraw_mask = redraw_mask;
   int ypos = MENU_TITLE2_YPOS;
   int font_nr = FONT_TITLE_2;
+  int x;
 
   if (ti->type == TREE_TYPE_LEVEL_NR)
     DrawTextFCentered(ypos, font_nr, leveldir_current->name);
 
+  if (ti->type == TREE_TYPE_SCORE_ENTRY)
+    DrawTextFCentered(ypos, font_nr, "HighScores of Level %d",
+                     scores.last_level_nr);
+
   if (ti->type != TREE_TYPE_LEVEL_DIR)
     return;
 
-  node_first = getTreeInfoFirstGroupEntry(ti);
-  node = getTreeInfoFromPos(node_first, entry_pos);
+  TreeInfo *node_first = getTreeInfoFirstGroupEntry(ti);
+  TreeInfo *node = getTreeInfoFromPos(node_first, entry_pos);
 
   DrawBackgroundForFont(SX, SY + ypos, SXSIZE, getFontHeight(font_nr), font_nr);
 
@@ -4746,10 +4925,50 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
     MarkTileDirty(x, 1);
 }
 
-static void drawChooseTreeCursorAndText(int y, boolean active, TreeInfo *ti)
+static void drawChooseTreeCursorAndText(TreeInfo *ti, boolean active)
+{
+  drawChooseTreeCursor(ti->cl_cursor, active);
+  drawChooseTreeText(ti, ti->cl_cursor, active);
+}
+
+static void drawChooseTreeScreen(TreeInfo *ti)
+{
+  drawChooseTreeHead(ti);
+  drawChooseTreeList(ti);
+  drawChooseTreeInfo(ti);
+  drawChooseTreeCursorAndText(ti, TRUE);
+
+  AdjustChooseTreeScrollbar(ti, SCREEN_CTRL_ID_SCROLL_VERTICAL);
+
+  // scroll bar and buttons may just have been added after reloading scores
+  if (game_status == GAME_MODE_SCORES)
+    MapScreenTreeGadgets(ti);
+}
+
+static TreeInfo *setHallOfFameActiveEntry(TreeInfo **ti_ptr)
 {
-  drawChooseTreeCursor(y, active);
-  drawChooseTreeText(y, active, ti);
+  int score_pos = scores.last_added;
+
+  if (game_status_last_screen == GAME_MODE_SCOREINFO)
+    score_pos = scores.last_entry_nr;
+
+  // set current tree entry to last added score entry
+  *ti_ptr = getTreeInfoFromIdentifier(score_entries, i_to_a(score_pos));
+
+  // if that fails, set current tree entry to first entry (back link)
+  if (*ti_ptr == NULL)
+    *ti_ptr = score_entries->node_group;
+
+  int num_entries = numTreeInfoInGroup(*ti_ptr);
+  int num_page_entries = MIN(num_entries, NUM_MENU_ENTRIES_ON_SCREEN);
+  int pos_score = getPosFromTreeInfo(*ti_ptr);
+  int pos_first_raw = pos_score - (num_page_entries + 1) / 2 + 1;
+  int pos_first = MIN(MAX(0, pos_first_raw), num_entries - num_page_entries);
+
+  (*ti_ptr)->cl_first = pos_first;
+  (*ti_ptr)->cl_cursor = pos_score - pos_first;
+
+  return *ti_ptr;
 }
 
 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
@@ -4759,15 +4978,33 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
   boolean has_scrollbar = screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->mapped;
   int mx_scrollbar = screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x;
   int mx_right_border = (has_scrollbar ? mx_scrollbar : SX + SXSIZE);
-  int sx1_edit_name = getChooseTreeEditXPos(POS_LEFT);
-  int sx2_edit_name = getChooseTreeEditXPos(POS_RIGHT);
+  int sx1_edit_name = getChooseTreeEditXPosReal(POS_LEFT);
+  int sx2_edit_name = getChooseTreeEditXPosReal(POS_RIGHT);
   int x = 0;
-  int y = ti->cl_cursor;
+  int y = (ti != NULL ? ti->cl_cursor : 0);
   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
   int num_entries = numTreeInfoInGroup(ti);
   int num_page_entries = MIN(num_entries, NUM_MENU_ENTRIES_ON_SCREEN);
   boolean position_set_by_scrollbar = (dx == 999);
 
+  if (game_status == GAME_MODE_SCORES)
+  {
+    if (server_scores.updated)
+    {
+      // reload scores, using updated server score cache file
+      LoadLocalAndServerScore(scores.last_level_nr, FALSE);
+
+      server_scores.updated = FALSE;
+
+      DrawHallOfFame_setScoreEntries();
+
+      ti = setHallOfFameActiveEntry(ti_ptr);
+
+      if (button != MB_MENU_INITIALIZE)
+       drawChooseTreeScreen(ti);
+    }
+  }
+
   if (button == MB_MENU_INITIALIZE)
   {
     int num_entries = numTreeInfoInGroup(ti);
@@ -4776,11 +5013,16 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     align_xoffset = getAlignXOffsetFromTreeInfo(ti);
     align_yoffset = getAlignYOffsetFromTreeInfo(ti);
 
-    if (ti->cl_first == -1)
+    if (game_status == GAME_MODE_SCORES)
+    {
+      ti = setHallOfFameActiveEntry(ti_ptr);
+    }
+    else if (ti->cl_first == -1)
     {
       // only on initialization
       ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
       ti->cl_cursor = entry_pos - ti->cl_first;
+
     }
     else if (ti->cl_cursor >= num_page_entries ||
             (num_entries > num_page_entries &&
@@ -4793,19 +5035,15 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
     if (position_set_by_scrollbar)
       ti->cl_first = dy;
-    else
-      AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
-                               ti->cl_first, ti);
 
-    drawChooseTreeList(ti->cl_first, num_page_entries, ti);
-    drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
-    drawChooseTreeCursorAndText(ti->cl_cursor, TRUE, ti);
+    drawChooseTreeScreen(ti);
 
     return;
   }
   else if (button == MB_MENU_LEAVE)
   {
-    FadeSetLeaveMenu();
+    if (game_status != GAME_MODE_SCORES)
+      FadeSetLeaveMenu();
 
     PlaySound(SND_MENU_ITEM_SELECTING);
 
@@ -4821,6 +5059,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
          setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
          setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
        execSetupGame();
+      else if (setup_mode == SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE ||
+              setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64 ||
+              setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV ||
+              setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_ATARI ||
+              setup_mode == SETUP_MODE_CHOOSE_BD_COLOR_TYPE)
+       execSetupEngines();
       else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
               setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
               setup_mode == SETUP_MODE_CHOOSE_RENDERING ||
@@ -4859,6 +5103,23 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     return;
   }
 
+#if defined(PLATFORM_ANDROID)
+  // directly continue when touching the screen after playing
+  if ((mx || my) && scores.continue_on_return)
+  {
+    // ignore touch events until released
+    mx = my = 0;
+  }
+#endif
+
+  // any mouse click or cursor key stops leaving scores by "Return" key
+  if ((mx || my || dx || dy) && scores.continue_on_return)
+  {
+    scores.continue_on_return = FALSE;
+    level_nr = scores.last_level_nr;
+    LoadLevel(level_nr);
+  }
+
   if (mx || my)                // mouse input
   {
     x = (mx - amSX) / 32;
@@ -4907,14 +5168,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       }
 
       if (redraw)
-      {
-       drawChooseTreeList(ti->cl_first, num_page_entries, ti);
-       drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
-       drawChooseTreeCursorAndText(ti->cl_cursor, TRUE, ti);
-
-       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
-                                 ti->cl_first, ti);
-      }
+       drawChooseTreeScreen(ti);
 
       return;
     }
@@ -4923,7 +5177,21 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     y = ti->cl_cursor + dy;
   }
 
-  if (dx == 1)
+  if (game_status == GAME_MODE_SCORES && ABS(dx) == 1)
+  {
+    HandleHallOfFame_SelectLevel(1, dx);
+
+    return;
+  }
+  else if (game_status == GAME_MODE_NAMES && dx == 1)
+  {
+    SetGameStatus(GAME_MODE_PSEUDO_TYPENAMES);
+
+    DrawTypeName();
+
+    return;
+  }
+  else if (dx == 1)
   {
     TreeInfo *node_first, *node_cursor;
     int entry_pos = ti->cl_first + y;
@@ -4939,15 +5207,17 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
       node_cursor->cl_first = ti->cl_first;
       node_cursor->cl_cursor = ti->cl_cursor;
+
       *ti_ptr = node_cursor->node_group;
       DrawChooseTree(ti_ptr);
 
       return;
     }
   }
-  else if (dx == -1 && ti->node_parent)
+  else if ((dx == -1 || button == MB_MENU_CONTINUE) && ti->node_parent)
   {
-    FadeSetLeaveMenu();
+    if (game_status != GAME_MODE_SCORES)
+      FadeSetLeaveMenu();
 
     PlaySound(SND_MENU_ITEM_SELECTING);
 
@@ -4974,11 +5244,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       {
        PlaySound(SND_MENU_ITEM_ACTIVATING);
 
-       drawChooseTreeCursorAndText(ti->cl_cursor, FALSE, ti);
-       drawChooseTreeCursorAndText(y, TRUE, ti);
-       drawChooseTreeInfo(ti->cl_first + y, ti);
+       drawChooseTreeCursorAndText(ti, FALSE);
 
        ti->cl_cursor = y;
+
+       drawChooseTreeCursorAndText(ti, TRUE);
+
+       drawChooseTreeInfo(ti);
       }
       else if (dx < 0)
       {
@@ -4989,6 +5261,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
              setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
              setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
            execSetupGame();
+         else if (setup_mode == SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64 ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_ATARI ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_COLOR_TYPE)
+           execSetupEngines();
          else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
                   setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
                   setup_mode == SETUP_MODE_CHOOSE_RENDERING ||
@@ -5028,22 +5306,26 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
        node_cursor->cl_first = ti->cl_first;
        node_cursor->cl_cursor = ti->cl_cursor;
+
        *ti_ptr = node_cursor->node_group;
        DrawChooseTree(ti_ptr);
       }
       else if (node_cursor->parent_link)
       {
-       FadeSetLeaveMenu();
+       if (game_status != GAME_MODE_SCORES)
+         FadeSetLeaveMenu();
 
        *ti_ptr = node_cursor->node_parent;
        DrawChooseTree(ti_ptr);
       }
       else
       {
-       FadeSetEnterMenu();
+       if (game_status != GAME_MODE_SCORES)
+         FadeSetEnterMenu();
 
        node_cursor->cl_first = ti->cl_first;
        node_cursor->cl_cursor = ti->cl_cursor;
+
        *ti_ptr = node_cursor;
 
        if (ti->type == TREE_TYPE_LEVEL_DIR)
@@ -5062,6 +5344,12 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
              setup_mode == SETUP_MODE_CHOOSE_SCROLL_DELAY ||
              setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
            execSetupGame();
+         else if (setup_mode == SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64 ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_ATARI ||
+                  setup_mode == SETUP_MODE_CHOOSE_BD_COLOR_TYPE)
+           execSetupEngines();
          else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE ||
                   setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE ||
                   setup_mode == SETUP_MODE_CHOOSE_RENDERING ||
@@ -5095,6 +5383,9 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
          {
            // store level set if chosen from "last played level set" menu
            StoreLastPlayedLevels(leveldir_current);
+
+           // store if level set chosen from "last played level set" menu
+           SaveLevelSetup_LastSeries();
          }
          else if (game_status == GAME_MODE_NAMES)
          {
@@ -5132,6 +5423,23 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
            ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_SOUNDS);
            ChangeCurrentArtworkIfNeeded(ARTWORK_TYPE_MUSIC);
          }
+         else if (game_status == GAME_MODE_SCORES)
+         {
+           if (scores.continue_playing && scores.continue_on_return)
+           {
+             StartPlayingFromHallOfFame();
+
+             return;
+           }
+           else if (!scores.continue_on_return)
+           {
+             SetGameStatus(GAME_MODE_SCOREINFO);
+
+             DrawScoreInfo(node_cursor->pos);
+
+             return;
+           }
+         }
 
          SetGameStatus(GAME_MODE_MAIN);
 
@@ -5140,14 +5448,15 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       }
     }
   }
+
+  if (game_status == GAME_MODE_SCORES)
+    PlayMenuSoundIfLoop();
 }
 
 void DrawChoosePlayerName(void)
 {
   int i;
 
-  FadeMenuSoundsAndMusic();
-
   if (player_name != NULL)
   {
     freeTreeInfo(player_name);
@@ -5186,9 +5495,10 @@ void DrawChoosePlayerName(void)
   if (player_name_current == NULL)
     player_name_current = player_name;
 
-  DrawChooseTree(&player_name_current);
+  // set text size for main name input (also used on name selection screen)
+  InitializeMainControls();
 
-  PlayMenuSoundsAndMusic();
+  DrawChooseTree(&player_name_current);
 }
 
 void HandleChoosePlayerName(int mx, int my, int dx, int dy, int button)
@@ -5198,11 +5508,7 @@ void HandleChoosePlayerName(int mx, int my, int dx, int dy, int button)
 
 void DrawChooseLevelSet(void)
 {
-  FadeMenuSoundsAndMusic();
-
   DrawChooseTree(&leveldir_current);
-
-  PlayMenuSoundsAndMusic();
 }
 
 void HandleChooseLevelSet(int mx, int my, int dx, int dy, int button)
@@ -5214,8 +5520,6 @@ void DrawChooseLevelNr(void)
 {
   int i;
 
-  FadeMenuSoundsAndMusic();
-
   if (level_number != NULL)
   {
     freeTreeInfo(level_number);
@@ -5261,8 +5565,6 @@ void DrawChooseLevelNr(void)
     level_number_current = level_number;
 
   DrawChooseTree(&level_number_current);
-
-  PlayMenuSoundsAndMusic();
 }
 
 void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
@@ -5270,15 +5572,69 @@ void HandleChooseLevelNr(int mx, int my, int dx, int dy, int button)
   HandleChooseTree(mx, my, dx, dy, button, &level_number_current);
 }
 
-void DrawHallOfFame(int level_nr)
+static void DrawHallOfFame_setScoreEntries(void)
 {
-  int fade_mask = REDRAW_FIELD;
+  int max_empty_entries = 10;  // at least show "top ten" list, if empty
+  int max_visible_entries = NUM_MENU_ENTRIES_ON_SCREEN - 1;   // w/o back link
+  int min_score_entries = MIN(max_empty_entries, max_visible_entries);
+  int score_pos = (scores.last_added >= 0 ? scores.last_added : 0);
+  int i;
 
-  if (CheckFadeAll())
-    fade_mask = REDRAW_ALL;
+  if (score_entries != NULL)
+  {
+    freeTreeInfo(score_entries);
 
-  UnmapAllGadgets();
-  FadeMenuSoundsAndMusic();
+    score_entries = NULL;
+  }
+
+  for (i = 0; i < MAX_SCORE_ENTRIES; i++)
+  {
+    // do not add empty score entries if off-screen
+    if (scores.entry[i].score == 0 &&
+       scores.entry[i].time == 0 &&
+       i >= min_score_entries)
+      break;
+
+    TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_SCORE_ENTRY);
+    char identifier[32], name[64];
+    int value = i;
+
+    ti->node_top = &score_entries;
+    ti->sort_priority = 10000 + value;
+    ti->color = FC_YELLOW;
+    ti->pos = i;
+
+    snprintf(identifier, sizeof(identifier), "%d", value);
+    snprintf(name, sizeof(name), "%03d.", value + 1);
+
+    setString(&ti->identifier, identifier);
+    setString(&ti->name, name);
+    setString(&ti->name_sorting, name);
+
+    pushTreeInfo(&score_entries, ti);
+  }
+
+  // sort score entries to start with highest score entry
+  sortTreeInfo(&score_entries);
+
+  // add top tree node to create back link to main menu
+  score_entries = addTopTreeInfoNode(score_entries);
+
+  // set current score entry to last added or highest score entry
+  score_entry_current =
+    getTreeInfoFromIdentifier(score_entries, i_to_a(score_pos));
+
+  // if that fails, set current score entry to first valid score entry
+  if (score_entry_current == NULL)
+    score_entry_current = getFirstValidTreeInfoEntry(score_entries);
+
+  if (score_entries != NULL && scores.continue_playing)
+    setString(&score_entries->node_group->name, BACKLINK_TEXT_NEXT);
+}
+
+void DrawHallOfFame(int nr)
+{
+  scores.last_level_nr = nr;
 
   // (this is needed when called from GameEnd() after winning a game)
   KeyboardAutoRepeatOn();
@@ -5287,180 +5643,341 @@ void DrawHallOfFame(int level_nr)
   SetDrawDeactivationMask(REDRAW_NONE);
   SetDrawBackgroundMask(REDRAW_FIELD);
 
-  LoadLocalAndServerScore(level_nr, TRUE);
+  LoadLocalAndServerScore(scores.last_level_nr, TRUE);
+
+  DrawHallOfFame_setScoreEntries();
 
   if (scores.last_added >= 0)
     SetAnimStatus(GAME_MODE_PSEUDO_SCORESNEW);
 
   FadeSetEnterScreen();
 
-  FadeOut(fade_mask);
+  DrawChooseTree(&score_entry_current);
+}
+
+static char *getHallOfFameRankText(int nr, int size)
+{
+  static char rank_text[10];
+  boolean forced = (scores.force_last_added && nr == scores.last_added);
+  char *rank_text_raw = (forced ? "???" : int2str(nr + 1, size));
+
+  sprintf(rank_text, "%s%s", rank_text_raw, (size > 0 || !forced ? "." : ""));
+
+  return rank_text;
+}
+
+static char *getHallOfFameTimeText(int nr)
+{
+  static char score_text[10];
+  int time_seconds = scores.entry[nr].time / FRAMES_PER_SECOND;
+  int mm = (time_seconds / 60) % 60;
+  int ss = (time_seconds % 60);
+
+  sprintf(score_text, "%02d:%02d", mm, ss);    // show playing time
+
+  return score_text;
+}
+
+static char *getHallOfFameScoreText(int nr, int size)
+{
+  if (!level.rate_time_over_score)
+    return int2str(scores.entry[nr].score, size);      // show normal score
+  else if (level.use_step_counter)
+    return int2str(scores.entry[nr].time, size);       // show number of steps
+  else
+    return getHallOfFameTimeText(nr);                  // show playing time
+}
+
+static char *getHallOfFameTapeDateText(struct ScoreEntry *entry)
+{
+  static char tape_date[MAX_ISO_DATE_LEN + 1];
+  int i, j;
+
+  if (!strEqual(entry->tape_date, UNKNOWN_NAME) ||
+      strEqual(entry->tape_basename, UNDEFINED_FILENAME))
+    return entry->tape_date;
+
+  for (i = 0, j = 0; i < 8; i++, j++)
+  {
+    tape_date[j] = entry->tape_basename[i];
+
+    if (i == 3 || i == 5)
+      tape_date[++j] = '-';
+  }
+
+  tape_date[MAX_ISO_DATE_LEN] = '\0';
+
+  return tape_date;
+}
+
+static void HandleHallOfFame_SelectLevel(int step, int direction)
+{
+  int old_level_nr = scores.last_level_nr;
+  int new_level_nr = old_level_nr + step * direction;
+
+  if (new_level_nr < leveldir_current->first_level)
+    new_level_nr = leveldir_current->first_level;
+  if (new_level_nr > leveldir_current->last_level)
+    new_level_nr = leveldir_current->last_level;
+
+  if (setup.allow_skipping_levels != STATE_TRUE && new_level_nr > leveldir_current->handicap_level)
+    new_level_nr = leveldir_current->handicap_level;
+
+  if (new_level_nr != old_level_nr)
+  {
+    PlaySound(SND_MENU_ITEM_SELECTING);
+
+    scores.last_level_nr = level_nr = new_level_nr;
+    scores.last_entry_nr = 0;
+
+    LoadLevel(level_nr);
+    LoadLocalAndServerScore(level_nr, TRUE);
+
+    DrawHallOfFame_setScoreEntries();
+
+    if (game_status == GAME_MODE_SCORES)
+    {
+      // force remapping optional gadgets (especially scroll bar)
+      UnmapScreenTreeGadgets();
+
+      // redraw complete high score screen, as sub-title has changed
+      ClearField();
+
+      // redraw level selection buttons (which have just been erased)
+      RedrawScreenMenuGadgets(SCREEN_MASK_SCORES);
+
+      HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, &score_entry_current);
+    }
+    else
+    {
+      DrawScoreInfo_Content(scores.last_entry_nr);
+    }
+
+    SaveLevelSetup_SeriesInfo();
+  }
+}
+
+void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
+{
+  HandleChooseTree(mx, my, dx, dy, button, &score_entry_current);
+}
+
+static void DrawScoreInfo_Content(int entry_nr)
+{
+  struct ScoreEntry *entry = &scores.entry[entry_nr];
+  char *pos_text = getHallOfFameRankText(entry_nr, 0);
+  char *tape_date = getHallOfFameTapeDateText(entry);
+  int font_head = MENU_INFO_FONT_HEAD;
+  int font_text = MENU_INFO_FONT_TEXT;
+  int font_foot = MENU_INFO_FONT_FOOT;
+  int spacing_para = menu.paragraph_spacing[GAME_MODE_SCOREINFO];
+  int spacing_line = menu.line_spacing[GAME_MODE_SCOREINFO];
+  int spacing_left = menu.left_spacing[GAME_MODE_SCOREINFO];
+  int spacing_top  = menu.top_spacing[GAME_MODE_SCOREINFO];
+  int xstep = getFontWidth(font_text);
+  int ystep_para = getMenuTextStep(spacing_para,  font_text);
+  int ystep_line = getMenuTextStep(spacing_line,  font_text);
+  int xstart  = mSX - SX + spacing_left;
+  int ystart  = mSY - SY + spacing_top + getHeadlineSpacing();
+  int ybottom = mSY - SY + SYSIZE - menu.bottom_spacing[GAME_MODE_SCOREINFO];
+  int xstart1 = xstart + xstep;
+  int xstart2 = xstart + xstep * 12;
+  int select_x = SX + xstart1;
+  int select_y1, select_y2;
+  int play_x, play_y;
+  int play_height = screen_gadget[SCREEN_CTRL_ID_PLAY_TAPE]->height;
+  boolean play_visible = !strEqual(tape_date, UNKNOWN_NAME);
+  int font_width = getFontWidth(font_text);
+  int font_height = getFontHeight(font_text);
+  int tape_date_width = getTextWidth(tape_date, font_text);
+  int pad_left = xstart2;
+  int pad_right = menu.right_spacing[GAME_MODE_SCOREINFO];
+  int max_chars_per_line = (SXSIZE - pad_left - pad_right) / font_width;
+  int max_lines_per_text = 5;
+  int lines;
+
+  ClearField();
+
+  // redraw level selection buttons (which have just been erased)
+  RedrawScreenMenuGadgets(SCREEN_MASK_SCORES);
+
+  drawChooseTreeHead(score_entries);
+  drawChooseTreeInfo(score_entries);
+
+  DrawTextF(xstart1, ystart, font_head, "Level Set");
+  lines = DrawTextBufferS(xstart2, ystart, leveldir_current->name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_line + (lines > 0 ? lines - 1 : 0) * font_height;
+
+  DrawTextF(xstart1, ystart, font_head, "Level");
+  lines = DrawTextBufferS(xstart2, ystart, level.name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_para + (lines > 0 ? lines - 1 : 0) * font_height;
+
+  select_y1 = SY + ystart;
+  ystart += graphic_info[IMG_MENU_BUTTON_PREV_SCORE].height;
+
+  DrawTextF(xstart1, ystart, font_head, "Rank");
+  DrawTextF(xstart2, ystart, font_text, pos_text);
+  ystart += ystep_line;
+
+  DrawTextF(xstart1, ystart, font_head, "Player");
+  DrawTextF(xstart2, ystart, font_text, entry->name);
+  ystart += ystep_line;
+
+  if (level.use_step_counter)
+  {
+    DrawTextF(xstart1, ystart, font_head, "Steps");
+    DrawTextF(xstart2, ystart, font_text, int2str(entry->time, 5));
+    ystart += ystep_line;
+  }
+  else
+  {
+    DrawTextF(xstart1, ystart, font_head, "Time");
+    DrawTextF(xstart2, ystart, font_text, getHallOfFameTimeText(entry_nr));
+    ystart += ystep_line;
+  }
+
+  if (!level.rate_time_over_score || entry->score > 0)
+  {
+    DrawTextF(xstart1, ystart, font_head, "Score");
+    DrawTextF(xstart2, ystart, font_text, int2str(entry->score, 5));
+    ystart += ystep_line;
+  }
+
+  ystart += ystep_line;
+
+  play_x = SX + xstart2 + tape_date_width + font_width;
+  play_y = SY + ystart + (font_height - play_height) / 2;
+
+  DrawTextF(xstart1, ystart, font_head, "Tape Date");
+  DrawTextF(xstart2, ystart, font_text, tape_date);
+  ystart += ystep_line;
 
-  // needed if different viewport properties defined for scores
-  ChangeViewportPropertiesIfNeeded();
+  DrawTextF(xstart1, ystart, font_head, "Platform");
+  DrawTextF(xstart2, ystart, font_text, entry->platform);
+  ystart += ystep_line;
 
-  PlayMenuSoundsAndMusic();
+  DrawTextF(xstart1, ystart, font_head, "Version");
+  DrawTextF(xstart2, ystart, font_text, entry->version);
+  ystart += ystep_line;
 
-  OpenDoor(GetDoorState() | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+  DrawTextF(xstart1, ystart, font_head, "Country");
+  lines = DrawTextBufferS(xstart2, ystart, entry->country_name, font_text,
+                         max_chars_per_line, -1, max_lines_per_text, 0, -1,
+                         TRUE, FALSE, FALSE);
+  ystart += ystep_line;
 
-  HandleHallOfFame(level_nr, 0, 0, 0, MB_MENU_INITIALIZE);
+  select_y2 = SY + ystart;
 
-  DrawMaskedBorder(fade_mask);
+  DrawTextSCentered(ybottom, font_foot, "Press any key or button to go back");
 
-  FadeIn(fade_mask);
+  AdjustScoreInfoButtons_SelectScore(select_x, select_y1, select_y2);
+  AdjustScoreInfoButtons_PlayTape(play_x, play_y, play_visible);
 }
 
-static int getHallOfFameFirstEntry(int first_entry, int step)
+static void DrawScoreInfo(int entry_nr)
 {
-  if (step == 0)
-    first_entry = scores.last_added - (NUM_MENU_ENTRIES_ON_SCREEN + 1) / 2 + 1;
-  else
-    first_entry += step;
+  scores.last_entry_nr = entry_nr;
+  score_info_tape_play = FALSE;
 
-  if (first_entry < 0)
-    first_entry = 0;
-  else if (first_entry > MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN)
-    first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
+  UnmapAllGadgets();
 
-  return first_entry;
-}
+  FreeScreenGadgets();
+  CreateScreenGadgets();
 
-static char *getHallOfFameScoreText(int nr)
-{
-  if (!level.rate_time_over_score)
-    return int2str(scores.entry[nr].score, 5); // show normal score
+  FadeOut(REDRAW_FIELD);
 
-  if (level.use_step_counter)
-    return int2str(scores.entry[nr].time, 5);  // show number of steps
+  // needed if different viewport properties defined after playing score tape
+  ChangeViewportPropertiesIfNeeded();
 
-  static char score_text[10];
-  int time_seconds = scores.entry[nr].time / FRAMES_PER_SECOND;
-  int mm = (time_seconds / 60) % 60;
-  int ss = (time_seconds % 60);
+  // set this after "ChangeViewportPropertiesIfNeeded()" (which may reset it)
+  SetDrawDeactivationMask(REDRAW_NONE);
+  SetDrawBackgroundMask(REDRAW_FIELD);
 
-  sprintf(score_text, "%02d:%02d", mm, ss);    // show playing time
+  // needed if different background image defined after playing score tape
+  SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_SCOREINFO);
 
-  return score_text;
+  // special compatibility handling for "Snake Bite" graphics set
+  if (strPrefix(leveldir_current->identifier, "snake_bite"))
+    ClearRectangle(gfx.background_bitmap, gfx.real_sx, gfx.real_sy + 64,
+                  gfx.full_sxsize, gfx.full_sysize - 64);
+
+  DrawScoreInfo_Content(entry_nr);
+
+  // map gadgets for score info screen
+  MapScreenMenuGadgets(SCREEN_MASK_SCORES_INFO);
+
+  FadeIn(REDRAW_FIELD);
 }
 
-static void drawHallOfFameList(int level_nr, int first_entry)
+static void HandleScoreInfo_SelectScore(int step, int direction)
 {
-  int i, j;
-
-  SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
-  ClearField();
+  int old_entry_nr = scores.last_entry_nr;
+  int new_entry_nr = old_entry_nr + step * direction;
+  int num_nodes = numTreeInfoInGroup(score_entry_current);
+  int num_entries = num_nodes - 1;     // score nodes only, without back link
 
-  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
-  DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
-                   "HighScores of Level %d", level_nr);
+  if (new_entry_nr < 0)
+    new_entry_nr = 0;
+  if (new_entry_nr > num_entries - 1)
+    new_entry_nr = num_entries - 1;
 
-  for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
+  if (new_entry_nr != old_entry_nr)
   {
-    int entry = first_entry + i;
-    boolean active = (entry == scores.last_added);
-    boolean forced = (scores.force_last_added && active);
-    int font_nr1 = (active ? FONT_TEXT_1_ACTIVE : FONT_TEXT_1);
-    int font_nr2 = (active ? FONT_TEXT_2_ACTIVE : FONT_TEXT_2);
-    int font_nr3 = (active ? FONT_TEXT_3_ACTIVE : FONT_TEXT_3);
-    int font_nr4 = (active ? FONT_TEXT_4_ACTIVE : FONT_TEXT_4);
-    int dxoff = getFontDrawOffsetX(font_nr1);
-    int dx1 = 3 * getFontWidth(font_nr1);
-    int dx2 = dx1 + getFontWidth(font_nr1);
-    int dx3 = SXSIZE - 2 * (mSX - SX + dxoff) - 5 * getFontWidth(font_nr4);
-    int num_dots = (dx3 - dx2) / getFontWidth(font_nr3);
-    int sy = mSY + 64 + i * 32;
-    char *pos_text = (forced ? "???" : int2str(entry + 1, 3));
+    scores.last_entry_nr = new_entry_nr;
 
-    DrawText(mSX, sy, pos_text, font_nr1);
-    DrawText(mSX + dx1, sy, ".", font_nr1);
-
-    for (j = 0; j < num_dots; j++)
-      DrawText(mSX + dx2 + j * getFontWidth(font_nr3), sy, ".", font_nr3);
+    DrawScoreInfo_Content(new_entry_nr);
+  }
+}
 
-    if (!strEqual(scores.entry[entry].name, EMPTY_PLAYER_NAME))
-      DrawText(mSX + dx2, sy, scores.entry[entry].name, font_nr2);
+static void HandleScoreInfo_PlayTape(void)
+{
+  if (!PlayScoreTape(scores.last_entry_nr))
+  {
+    DrawScoreInfo_Content(scores.last_entry_nr);
 
-    DrawText(mSX + dx3, sy, getHallOfFameScoreText(entry), font_nr4);
+    FadeIn(REDRAW_FIELD);
   }
-
-  redraw_mask |= REDRAW_FIELD;
 }
 
-void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
+void HandleScoreInfo(int mx, int my, int dx, int dy, int button)
 {
-  static int level_nr = 0;
-  static int first_entry = 0;
-  int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
+  boolean button_action = (button == MB_MENU_LEAVE || button == MB_MENU_CHOICE);
+  boolean button_is_valid = (mx >= 0 && my >= 0);
+  boolean button_screen_clicked = (button_action && button_is_valid);
 
-  if (button == MB_MENU_INITIALIZE)
+  if (server_scores.updated)
   {
-    level_nr = mx;
-
-    if (server_scores.updated)
-    {
-      // reload scores, using updated server score cache file
-      LoadLocalAndServerScore(level_nr, FALSE);
-
-      server_scores.updated = FALSE;
-    }
+    // reload scores, using updated server score cache file
+    LoadLocalAndServerScore(scores.last_level_nr, FALSE);
 
-    first_entry = getHallOfFameFirstEntry(0, 0);
+    server_scores.updated = FALSE;
 
-    drawHallOfFameList(level_nr, first_entry);
+    DrawHallOfFame_setScoreEntries();
 
-    return;
+    DrawScoreInfo_Content(scores.last_entry_nr);
   }
 
-  if (ABS(dy) == SCROLL_PAGE)          // handle scrolling one page
-    step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
-
-  if (dy < 0)
+  if (button_screen_clicked)
   {
-    first_entry = getHallOfFameFirstEntry(first_entry, -step);
+    PlaySound(SND_MENU_ITEM_SELECTING);
 
-    drawHallOfFameList(level_nr, first_entry);
-  }
-  else if (dy > 0)
-  {
-    first_entry = getHallOfFameFirstEntry(first_entry, step);
+    SetGameStatus(GAME_MODE_SCORES);
 
-    drawHallOfFameList(level_nr, first_entry);
+    DrawHallOfFame(scores.last_level_nr);
   }
-  else if (button == MB_MENU_LEAVE || button == MB_MENU_CHOICE)
+  else if (dx)
   {
-    PlaySound(SND_MENU_ITEM_SELECTING);
-
-    FadeSound(SND_BACKGROUND_SCORES);
-
-    if (button == MB_MENU_CHOICE &&
-       game_status_last_screen == GAME_MODE_PLAYING &&
-       setup.auto_play_next_level && setup.increment_levels &&
-       level_nr < leveldir_current->last_level &&
-       !network_playing)
-    {
-      StartGameActions(network.enabled, setup.autorecord, level.random_seed);
-    }
-    else
-    {
-      SetGameStatus(GAME_MODE_MAIN);
-
-      DrawMainMenu();
-    }
+    HandleHallOfFame_SelectLevel(1, SIGN(dx) * (ABS(dx) > 1 ? 10 : 1));
   }
-  else if (server_scores.updated)
+  else if (dy)
   {
-    // reload scores, using updated server score cache file
-    LoadLocalAndServerScore(level_nr, FALSE);
-
-    server_scores.updated = FALSE;
-
-    first_entry = getHallOfFameFirstEntry(0, 0);
-
-    drawHallOfFameList(level_nr, first_entry);
+    HandleScoreInfo_SelectScore(1, SIGN(dy) * (ABS(dy) > 1 ? 10 : 1));
   }
-
-  if (game_status == GAME_MODE_SCORES)
-    PlayMenuSoundIfLoop();
 }
 
 
@@ -5478,6 +5995,11 @@ static char *rendering_mode_text;
 static char *vsync_mode_text;
 static char *scroll_delay_text;
 static char *snapshot_mode_text;
+static char *game_engine_type_text;
+static char *bd_palette_c64_text;
+static char *bd_palette_c64dtv_text;
+static char *bd_palette_atari_text;
+static char *bd_color_type_text;
 static char *game_speed_text;
 static char *scores_type_text;
 static char *network_server_text;
@@ -5653,7 +6175,7 @@ static void execSetupGame_setScrollDelays(void)
 
     // set current scroll delay value to configured scroll delay value
     scroll_delay_current =
-      getTreeInfoFromIdentifier(scroll_delays,i_to_a(setup.scroll_delay_value));
+      getTreeInfoFromIdentifier(scroll_delays, i_to_a(setup.scroll_delay_value));
 
     // if that fails, set current scroll delay to reliable default value
     if (scroll_delay_current == NULL)
@@ -5761,37 +6283,328 @@ static void execSetupGame(void)
     DisableVsyncIfNeeded();
 }
 
-static void execSetupChooseScoresType(void)
+static void execSetupChooseScoresType(void)
+{
+  setup_mode = SETUP_MODE_CHOOSE_SCORES_TYPE;
+
+  DrawSetupScreen();
+}
+
+static void execSetupChooseGameSpeed(void)
+{
+  setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
+
+  DrawSetupScreen();
+}
+
+static void execSetupChooseScrollDelay(void)
+{
+  setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
+
+  DrawSetupScreen();
+}
+
+static void execSetupChooseSnapshotMode(void)
+{
+  setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE;
+
+  DrawSetupScreen();
+}
+
+static void execSetupEngines_setGameEngineType(void)
+{
+  if (game_engine_types == NULL)
+  {
+    int i;
+
+    for (i = 0; game_engine_types_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = game_engine_types_list[i].value;
+      char *text = game_engine_types_list[i].text;
+
+      ti->node_top = &game_engine_types;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, STR_SETUP_CHOOSE_GAME_ENGINE_TYPE);
+
+      pushTreeInfo(&game_engine_types, ti);
+    }
+
+    // sort game engine type values to start with lowest game engine type value
+    sortTreeInfo(&game_engine_types);
+
+    // set current game engine type value to configured game engine type value
+    game_engine_type_current =
+      getTreeInfoFromIdentifier(game_engine_types, i_to_a(setup.default_game_engine_type));
+
+    // if that fails, set current game engine type to reliable default value
+    if (game_engine_type_current == NULL)
+      game_engine_type_current =
+       getTreeInfoFromIdentifier(game_engine_types, i_to_a(GAME_ENGINE_TYPE_RND));
+
+    // if that also fails, set current game engine type to first available value
+    if (game_engine_type_current == NULL)
+      game_engine_type_current = game_engine_types;
+  }
+
+  setup.default_game_engine_type = atoi(game_engine_type_current->identifier);
+
+  // needed for displaying game engine type text instead of identifier
+  game_engine_type_text = game_engine_type_current->name;
+}
+
+static void execSetupEngines_setPalettesC64(void)
+{
+  if (bd_palettes_c64 == NULL)
+  {
+    int i;
+
+    for (i = 0; bd_palettes_c64_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = bd_palettes_c64_list[i].value;
+      char *text = bd_palettes_c64_list[i].text;
+
+      ti->node_top = &bd_palettes_c64;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, STR_SETUP_CHOOSE_BD_PALETTE_C64);
+
+      pushTreeInfo(&bd_palettes_c64, ti);
+    }
+
+    // sort palette values to start with lowest palette value
+    sortTreeInfo(&bd_palettes_c64);
+
+    // set current palette value to configured palette value
+    bd_palette_c64_current =
+      getTreeInfoFromIdentifier(bd_palettes_c64, i_to_a(setup.bd_palette_c64));
+
+    // if that fails, set current palette to reliable default value
+    if (bd_palette_c64_current == NULL)
+      bd_palette_c64_current =
+       getTreeInfoFromIdentifier(bd_palettes_c64, i_to_a(GD_DEFAULT_PALETTE_C64));
+
+    // if that also fails, set current palette to first available value
+    if (bd_palette_c64_current == NULL)
+      bd_palette_c64_current = bd_palettes_c64;
+  }
+
+  setup.bd_palette_c64 = atoi(bd_palette_c64_current->identifier);
+
+  // needed for displaying palette text instead of identifier
+  bd_palette_c64_text = bd_palette_c64_current->name;
+}
+
+static void execSetupEngines_setPalettesC64DTV(void)
+{
+  if (bd_palettes_c64dtv == NULL)
+  {
+    int i;
+
+    for (i = 0; bd_palettes_c64dtv_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = bd_palettes_c64dtv_list[i].value;
+      char *text = bd_palettes_c64dtv_list[i].text;
+
+      ti->node_top = &bd_palettes_c64dtv;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, STR_SETUP_CHOOSE_BD_PALETTE_C64DTV);
+
+      pushTreeInfo(&bd_palettes_c64dtv, ti);
+    }
+
+    // sort palette values to start with lowest palette value
+    sortTreeInfo(&bd_palettes_c64dtv);
+
+    // set current palette value to configured palette value
+    bd_palette_c64dtv_current =
+      getTreeInfoFromIdentifier(bd_palettes_c64dtv, i_to_a(setup.bd_palette_c64dtv));
+
+    // if that fails, set current palette to reliable default value
+    if (bd_palette_c64dtv_current == NULL)
+      bd_palette_c64dtv_current =
+       getTreeInfoFromIdentifier(bd_palettes_c64dtv, i_to_a(GD_DEFAULT_PALETTE_C64DTV));
+
+    // if that also fails, set current palette to first available value
+    if (bd_palette_c64dtv_current == NULL)
+      bd_palette_c64dtv_current = bd_palettes_c64dtv;
+  }
+
+  setup.bd_palette_c64dtv = atoi(bd_palette_c64dtv_current->identifier);
+
+  // needed for displaying palette text instead of identifier
+  bd_palette_c64dtv_text = bd_palette_c64dtv_current->name;
+}
+
+static void execSetupEngines_setPalettesAtari(void)
+{
+  if (bd_palettes_atari == NULL)
+  {
+    int i;
+
+    for (i = 0; bd_palettes_atari_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = bd_palettes_atari_list[i].value;
+      char *text = bd_palettes_atari_list[i].text;
+
+      ti->node_top = &bd_palettes_atari;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, STR_SETUP_CHOOSE_BD_PALETTE_ATARI);
+
+      pushTreeInfo(&bd_palettes_atari, ti);
+    }
+
+    // sort palette values to start with lowest palette value
+    sortTreeInfo(&bd_palettes_atari);
+
+    // set current palette value to configured palette value
+    bd_palette_atari_current =
+      getTreeInfoFromIdentifier(bd_palettes_atari, i_to_a(setup.bd_palette_atari));
+
+    // if that fails, set current palette to reliable default value
+    if (bd_palette_atari_current == NULL)
+      bd_palette_atari_current =
+       getTreeInfoFromIdentifier(bd_palettes_atari, i_to_a(GD_DEFAULT_PALETTE_ATARI));
+
+    // if that also fails, set current palette to first available value
+    if (bd_palette_atari_current == NULL)
+      bd_palette_atari_current = bd_palettes_atari;
+  }
+
+  setup.bd_palette_atari = atoi(bd_palette_atari_current->identifier);
+
+  // needed for displaying palette text instead of identifier
+  bd_palette_atari_text = bd_palette_atari_current->name;
+}
+
+static void execSetupEngines_setColorType(void)
+{
+  if (bd_color_types == NULL)
+  {
+    int i;
+
+    for (i = 0; bd_color_types_list[i].value != -1; i++)
+    {
+      TreeInfo *ti = newTreeInfo_setDefaults(TREE_TYPE_UNDEFINED);
+      char identifier[32], name[32];
+      int value = bd_color_types_list[i].value;
+      char *text = bd_color_types_list[i].text;
+
+      ti->node_top = &bd_color_types;
+      ti->sort_priority = value;
+
+      sprintf(identifier, "%d", value);
+      sprintf(name, "%s", text);
+
+      setString(&ti->identifier, identifier);
+      setString(&ti->name, name);
+      setString(&ti->name_sorting, name);
+      setString(&ti->infotext, STR_SETUP_CHOOSE_BD_COLOR_TYPE);
+
+      pushTreeInfo(&bd_color_types, ti);
+    }
+
+    // sort color type values to start with lowest color type value
+    sortTreeInfo(&bd_color_types);
+
+    // set current color type value to configured color type value
+    bd_color_type_current =
+      getTreeInfoFromIdentifier(bd_color_types, i_to_a(setup.bd_default_color_type));
+
+    // if that fails, set current color type to reliable default value
+    if (bd_color_type_current == NULL)
+      bd_color_type_current =
+       getTreeInfoFromIdentifier(bd_color_types, i_to_a(GD_DEFAULT_COLOR_TYPE));
+
+    // if that also fails, set current color type to first available value
+    if (bd_color_type_current == NULL)
+      bd_color_type_current = bd_color_types;
+  }
+
+  setup.bd_default_color_type = atoi(bd_color_type_current->identifier);
+
+  // needed for displaying color type text instead of identifier
+  bd_color_type_text = bd_color_type_current->name;
+}
+
+static void execSetupEngines(void)
+{
+  setup_mode = SETUP_MODE_ENGINES;
+
+  execSetupEngines_setGameEngineType();
+  execSetupEngines_setPalettesC64();
+  execSetupEngines_setPalettesC64DTV();
+  execSetupEngines_setPalettesAtari();
+  execSetupEngines_setColorType();
+
+  DrawSetupScreen();
+}
+
+static void execSetupChooseGameEngineType(void)
 {
-  setup_mode = SETUP_MODE_CHOOSE_SCORES_TYPE;
+  setup_mode = SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE;
 
   DrawSetupScreen();
 }
 
-static void execSetupChooseGameSpeed(void)
+static void execSetupChoosePaletteC64(void)
 {
-  setup_mode = SETUP_MODE_CHOOSE_GAME_SPEED;
+  setup_mode = SETUP_MODE_CHOOSE_BD_PALETTE_C64;
 
   DrawSetupScreen();
 }
 
-static void execSetupChooseScrollDelay(void)
+static void execSetupChoosePaletteC64DTV(void)
 {
-  setup_mode = SETUP_MODE_CHOOSE_SCROLL_DELAY;
+  setup_mode = SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV;
 
   DrawSetupScreen();
 }
 
-static void execSetupChooseSnapshotMode(void)
+static void execSetupChoosePaletteAtari(void)
 {
-  setup_mode = SETUP_MODE_CHOOSE_SNAPSHOT_MODE;
+  setup_mode = SETUP_MODE_CHOOSE_BD_PALETTE_ATARI;
 
   DrawSetupScreen();
 }
 
-static void execSetupEngines(void)
+static void execSetupChooseColorType(void)
 {
-  setup_mode = SETUP_MODE_ENGINES;
+  setup_mode = SETUP_MODE_CHOOSE_BD_COLOR_TYPE;
 
   DrawSetupScreen();
 }
@@ -6213,7 +7026,7 @@ static void execSetupSound(void)
 
     // set current volume value to configured volume value
     volume_simple_current =
-      getTreeInfoFromIdentifier(volumes_simple,i_to_a(setup.volume_simple));
+      getTreeInfoFromIdentifier(volumes_simple, i_to_a(setup.volume_simple));
 
     // if that fails, set current volume to reliable default value
     if (volume_simple_current == NULL)
@@ -6281,7 +7094,7 @@ static void execSetupSound(void)
 
     // set current volume value to configured volume value
     volume_loops_current =
-      getTreeInfoFromIdentifier(volumes_loops,i_to_a(setup.volume_loops));
+      getTreeInfoFromIdentifier(volumes_loops, i_to_a(setup.volume_loops));
 
     // if that fails, set current volume to reliable default value
     if (volume_loops_current == NULL)
@@ -6349,7 +7162,7 @@ static void execSetupSound(void)
 
     // set current volume value to configured volume value
     volume_music_current =
-      getTreeInfoFromIdentifier(volumes_music,i_to_a(setup.volume_music));
+      getTreeInfoFromIdentifier(volumes_music, i_to_a(setup.volume_music));
 
     // if that fails, set current volume to reliable default value
     if (volume_music_current == NULL)
@@ -6816,6 +7629,13 @@ static void execSetupShortcuts5(void)
   DrawSetupScreen();
 }
 
+static void execSetupShortcuts6(void)
+{
+  setup_mode = SETUP_MODE_SHORTCUTS_6;
+
+  DrawSetupScreen();
+}
+
 static void execExitSetup(void)
 {
   SetGameStatus(GAME_MODE_MAIN);
@@ -6907,6 +7727,22 @@ static void ToggleGameSpeedsListIfNeeded(void)
   DrawSetupScreen();
 }
 
+static void ToggleUseApiServerIfNeeded(void)
+{
+  if (runtime.use_api_server == setup.use_api_server)
+    return;
+
+  runtime.use_api_server = setup.use_api_server;
+
+  if (runtime.use_api_server)
+  {
+    if (setup.has_remaining_tapes)
+      setup.ask_for_uploading_tapes = TRUE;
+
+    CheckApiServerTasks();
+  }
+}
+
 static void ModifyGameSpeedIfNeeded(void)
 {
   if (strEqual(setup.vsync_mode, STR_VSYNC_MODE_OFF) ||
@@ -6954,85 +7790,119 @@ static struct
   void *related_value;
 } hide_related_entry_list[] =
 {
-  { &setup.scores_in_highscore_list,   execSetupChooseScoresType       },
-  { &setup.scores_in_highscore_list,   &scores_type_text               },
+  { &setup.network_server_hostname,            execGadgetNetworkServer         },
+  { &setup.network_server_hostname,            &network_server_text            },
+
+  { &setup.scores_in_highscore_list,           execSetupChooseScoresType       },
+  { &setup.scores_in_highscore_list,           &scores_type_text               },
+
+  { &setup.game_frame_delay,                   execSetupChooseGameSpeed        },
+  { &setup.game_frame_delay,                   &game_speed_text                },
+
+  { &setup.scroll_delay_value,                 execSetupChooseScrollDelay      },
+  { &setup.scroll_delay_value,                 &scroll_delay_text              },
+
+  { &setup.engine_snapshot_mode,               execSetupChooseSnapshotMode     },
+  { &setup.engine_snapshot_mode,               &snapshot_mode_text             },
+
+  { &setup.default_game_engine_type,           execSetupChooseGameEngineType   },
+  { &setup.default_game_engine_type,           &game_engine_type_text          },
+
+  { &setup.bd_palette_c64,                     execSetupChoosePaletteC64       },
+  { &setup.bd_palette_c64,                     &bd_palette_c64_text            },
 
-  { &setup.game_frame_delay,           execSetupChooseGameSpeed        },
-  { &setup.game_frame_delay,           &game_speed_text                },
+  { &setup.bd_palette_c64dtv,                  execSetupChoosePaletteC64DTV    },
+  { &setup.bd_palette_c64dtv,                  &bd_palette_c64dtv_text         },
 
-  { &setup.scroll_delay_value,         execSetupChooseScrollDelay      },
-  { &setup.scroll_delay_value,         &scroll_delay_text              },
+  { &setup.bd_palette_atari,                   execSetupChoosePaletteAtari     },
+  { &setup.bd_palette_atari,                   &bd_palette_atari_text          },
 
-  { &setup.engine_snapshot_mode,       execSetupChooseSnapshotMode     },
-  { &setup.engine_snapshot_mode,       &snapshot_mode_text             },
+  { &setup.bd_default_color_type,              execSetupChooseColorType        },
+  { &setup.bd_default_color_type,              &bd_color_type_text             },
 
-  { &setup.window_scaling_percent,     execSetupChooseWindowSize       },
-  { &setup.window_scaling_percent,     &window_size_text               },
+  { &setup.window_scaling_percent,             execSetupChooseWindowSize       },
+  { &setup.window_scaling_percent,             &window_size_text               },
 
-  { &setup.window_scaling_quality,     execSetupChooseScalingType      },
-  { &setup.window_scaling_quality,     &scaling_type_text              },
+  { &setup.window_scaling_quality,             execSetupChooseScalingType      },
+  { &setup.window_scaling_quality,             &scaling_type_text              },
 
-  { &setup.screen_rendering_mode,      execSetupChooseRenderingMode    },
-  { &setup.screen_rendering_mode,      &rendering_mode_text            },
+  { &setup.screen_rendering_mode,              execSetupChooseRenderingMode    },
+  { &setup.screen_rendering_mode,              &rendering_mode_text            },
 
-  { &setup.vsync_mode,                 execSetupChooseVsyncMode        },
-  { &setup.vsync_mode,                 &vsync_mode_text                },
+  { &setup.vsync_mode,                         execSetupChooseVsyncMode        },
+  { &setup.vsync_mode,                         &vsync_mode_text                },
 
-  { &setup.graphics_set,               execSetupChooseGraphics         },
-  { &setup.graphics_set,               &graphics_set_name              },
+  { &setup.graphics_set,                       execSetupChooseGraphics         },
+  { &setup.graphics_set,                       &graphics_set_name              },
 
-  { &setup.sounds_set,                 execSetupChooseSounds           },
-  { &setup.sounds_set,                 &sounds_set_name                },
+  { &setup.sounds_set,                         execSetupChooseSounds           },
+  { &setup.sounds_set,                         &sounds_set_name                },
 
-  { &setup.music_set,                  execSetupChooseMusic            },
-  { &setup.music_set,                  &music_set_name                 },
+  { &setup.music_set,                          execSetupChooseMusic            },
+  { &setup.music_set,                          &music_set_name                 },
 
-  { &setup.volume_simple,              execSetupChooseVolumeSimple     },
-  { &setup.volume_simple,              &volume_simple_text             },
+  { &setup.volume_simple,                      execSetupChooseVolumeSimple     },
+  { &setup.volume_simple,                      &volume_simple_text             },
 
-  { &setup.volume_loops,               execSetupChooseVolumeLoops      },
-  { &setup.volume_loops,               &volume_loops_text              },
+  { &setup.volume_loops,                       execSetupChooseVolumeLoops      },
+  { &setup.volume_loops,                       &volume_loops_text              },
 
-  { &setup.volume_music,               execSetupChooseVolumeMusic      },
-  { &setup.volume_music,               &volume_music_text              },
+  { &setup.volume_music,                       execSetupChooseVolumeMusic      },
+  { &setup.volume_music,                       &volume_music_text              },
 
-  { &setup.touch.control_type,         execSetupChooseTouchControls    },
-  { &setup.touch.control_type,         &touch_controls_text            },
+  { &setup.touch.control_type,                 execSetupChooseTouchControls    },
+  { &setup.touch.control_type,                 &touch_controls_text            },
 
-  { &setup.touch.move_distance,                execSetupChooseMoveDistance     },
-  { &setup.touch.move_distance,                &move_distance_text             },
+  { &setup.touch.move_distance,                        execSetupChooseMoveDistance     },
+  { &setup.touch.move_distance,                        &move_distance_text             },
 
-  { &setup.touch.drop_distance,                execSetupChooseDropDistance     },
-  { &setup.touch.drop_distance,                &drop_distance_text             },
+  { &setup.touch.drop_distance,                        execSetupChooseDropDistance     },
+  { &setup.touch.drop_distance,                        &drop_distance_text             },
 
-  { &setup.touch.transparency,         execSetupChooseTransparency     },
-  { &setup.touch.transparency,         &transparency_text              },
+  { &setup.touch.transparency,                 execSetupChooseTransparency     },
+  { &setup.touch.transparency,                 &transparency_text              },
 
-  { &setup.touch.grid_xsize[0],                execSetupChooseGridXSize_0      },
-  { &setup.touch.grid_xsize[0],                &grid_size_text[0][0]           },
+  { &setup.touch.grid_xsize[0],                        execSetupChooseGridXSize_0      },
+  { &setup.touch.grid_xsize[0],                        &grid_size_text[0][0]           },
 
-  { &setup.touch.grid_ysize[0],                execSetupChooseGridYSize_0      },
-  { &setup.touch.grid_ysize[0],                &grid_size_text[0][1]           },
+  { &setup.touch.grid_ysize[0],                        execSetupChooseGridYSize_0      },
+  { &setup.touch.grid_ysize[0],                        &grid_size_text[0][1]           },
 
-  { &setup.touch.grid_xsize[1],                execSetupChooseGridXSize_1      },
-  { &setup.touch.grid_xsize[1],                &grid_size_text[1][0]           },
+  { &setup.touch.grid_xsize[1],                        execSetupChooseGridXSize_1      },
+  { &setup.touch.grid_xsize[1],                        &grid_size_text[1][0]           },
 
-  { &setup.touch.grid_ysize[1],                execSetupChooseGridYSize_1      },
-  { &setup.touch.grid_ysize[1],                &grid_size_text[1][1]           },
+  { &setup.touch.grid_ysize[1],                        execSetupChooseGridYSize_1      },
+  { &setup.touch.grid_ysize[1],                        &grid_size_text[1][1]           },
 
-  { &setup.internal.menu_game,         execSetupGame                   },
-  { &setup.internal.menu_engines,      execSetupEngines                },
-  { &setup.internal.menu_editor,       execSetupEditor                 },
-  { &setup.internal.menu_graphics,     execSetupGraphics               },
-  { &setup.internal.menu_sound,                execSetupSound                  },
-  { &setup.internal.menu_artwork,      execSetupArtwork                },
-  { &setup.internal.menu_input,                execSetupInput                  },
-  { &setup.internal.menu_touch,                execSetupTouch                  },
-  { &setup.internal.menu_shortcuts,    execSetupShortcuts              },
-  { &setup.internal.menu_exit,         execExitSetup                   },
-  { &setup.internal.menu_save_and_exit,        execSaveAndExitSetup            },
+  { &setup.internal.menu_game,                 execSetupGame                   },
+  { &setup.internal.menu_engines,              execSetupEngines                },
+  { &setup.internal.menu_editor,               execSetupEditor                 },
+  { &setup.internal.menu_graphics,             execSetupGraphics               },
+  { &setup.internal.menu_sound,                        execSetupSound                  },
+  { &setup.internal.menu_artwork,              execSetupArtwork                },
+  { &setup.internal.menu_input,                        execSetupInput                  },
+  { &setup.internal.menu_touch,                        execSetupTouch                  },
+  { &setup.internal.menu_shortcuts,            execSetupShortcuts              },
+  { &setup.internal.menu_exit,                 execExitSetup                   },
+  { &setup.internal.menu_save_and_exit,                execSaveAndExitSetup            },
 
-  { NULL,                              NULL                            }
+  { &setup.internal.menu_shortcuts_various,    execSetupShortcuts1             },
+  { &setup.internal.menu_shortcuts_focus,      execSetupShortcuts2             },
+  { &setup.internal.menu_shortcuts_tape,       execSetupShortcuts3             },
+  { &setup.internal.menu_shortcuts_sound,      execSetupShortcuts4             },
+  { &setup.internal.menu_shortcuts_snap,       execSetupShortcuts5             },
+  { &setup.internal.menu_shortcuts_speed,      execSetupShortcuts6             },
+
+  { &setup.internal.info_title,                        execInfoTitleScreen             },
+  { &setup.internal.info_elements,             execInfoElements                },
+  { &setup.internal.info_music,                        execInfoMusic                   },
+  { &setup.internal.info_credits,              execInfoCredits                 },
+  { &setup.internal.info_program,              execInfoProgram                 },
+  { &setup.internal.info_version,              execInfoVersion                 },
+  { &setup.internal.info_levelset,             execInfoLevelSet                },
+  { &setup.internal.info_exit,                 execExitInfo                    },
+
+  { NULL,                                      NULL                            }
 };
 
 void setHideRelatedSetupEntries(void)
@@ -7046,251 +7916,285 @@ void setHideRelatedSetupEntries(void)
 
 static struct TokenInfo setup_info_main[] =
 {
-  { TYPE_ENTER_MENU,   execSetupGame,          STR_SETUP_GAME          },
-  { TYPE_ENTER_MENU,   execSetupEngines,       STR_SETUP_ENGINES       },
-  { TYPE_ENTER_MENU,   execSetupEditor,        STR_SETUP_EDITOR        },
-  { TYPE_ENTER_MENU,   execSetupGraphics,      STR_SETUP_GRAPHICS      },
-  { TYPE_ENTER_MENU,   execSetupSound,         STR_SETUP_SOUND         },
-  { TYPE_ENTER_MENU,   execSetupArtwork,       STR_SETUP_ARTWORK       },
-  { TYPE_ENTER_MENU,   execSetupInput,         STR_SETUP_INPUT         },
-  { TYPE_ENTER_MENU,   execSetupTouch,         STR_SETUP_TOUCH         },
-  { TYPE_ENTER_MENU,   execSetupShortcuts,     STR_SETUP_SHORTCUTS     },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execExitSetup,          STR_SETUP_EXIT          },
-  { TYPE_LEAVE_MENU,   execSaveAndExitSetup,   STR_SETUP_SAVE_AND_EXIT },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_MENU,   execSetupGame,                  STR_SETUP_GAME                  },
+  { TYPE_ENTER_MENU,   execSetupEngines,               STR_SETUP_ENGINES               },
+  { TYPE_ENTER_MENU,   execSetupEditor,                STR_SETUP_EDITOR                },
+  { TYPE_ENTER_MENU,   execSetupGraphics,              STR_SETUP_GRAPHICS              },
+  { TYPE_ENTER_MENU,   execSetupSound,                 STR_SETUP_SOUND                 },
+  { TYPE_ENTER_MENU,   execSetupArtwork,               STR_SETUP_ARTWORK               },
+  { TYPE_ENTER_MENU,   execSetupInput,                 STR_SETUP_INPUT                 },
+  { TYPE_ENTER_MENU,   execSetupTouch,                 STR_SETUP_TOUCH                 },
+  { TYPE_ENTER_MENU,   execSetupShortcuts,             STR_SETUP_SHORTCUTS             },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execExitSetup,                  STR_SETUP_EXIT                  },
+  { TYPE_LEAVE_MENU,   execSaveAndExitSetup,           STR_SETUP_SAVE_AND_EXIT         },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_game[] =
 {
-  { TYPE_SWITCH,       &setup.team_mode,       "Team-Mode (Multi-Player):" },
-  { TYPE_SWITCH,       &setup.network_mode,    "Network Multi-Player Mode:" },
-  { TYPE_PLAYER,       &setup.network_player_nr,"Preferred Network Player:" },
-  { TYPE_TEXT_INPUT,   execGadgetNetworkServer, "Network Server Hostname:" },
-  { TYPE_STRING,       &network_server_text,   ""                      },
-  { TYPE_SWITCH,       &setup.use_api_server,  "Use Highscore Server:" },
-  { TYPE_ENTER_LIST,   execSetupChooseScoresType,"Scores in Highscore List:" },
-  { TYPE_STRING,       &scores_type_text,      ""                      },
-  { TYPE_ENTER_LIST,   execOfferUploadTapes,   "Upload All Tapes to Server" },
-  { TYPE_SWITCH,       &setup.multiple_users,  "Multiple Users/Teams:" },
-  { TYPE_YES_NO,       &setup.input_on_focus,  "Only Move Focussed Player:" },
-  { TYPE_SWITCH,       &setup.time_limit,      "Time Limit:"           },
-  { TYPE_SWITCH,       &setup.handicap,        "Handicap:"             },
-  { TYPE_SWITCH,       &setup.skip_levels,     "Skip Unsolved Levels:" },
-  { TYPE_SWITCH,       &setup.increment_levels,"Increment Solved Levels:" },
-  { TYPE_SWITCH,       &setup.auto_play_next_level,"Auto-play Next Level:" },
-  { TYPE_SWITCH,       &setup.count_score_after_game,"Count Score After Game:" },
-  { TYPE_SWITCH,       &setup.show_scores_after_game,"Show Scores After Game:" },
-  { TYPE_YES_NO,       &setup.ask_on_game_over, "Ask on Game Over:"    },
-  { TYPE_YES_NO,       &setup.ask_on_quit_game, "Ask on Quit Game:"    },
-  { TYPE_YES_NO,       &setup.ask_on_quit_program, "Ask on Quit Program:" },
-  { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record Tapes:"    },
-  { TYPE_ENTER_LIST,   execSetupChooseGameSpeed, "Game Speed:"         },
-  { TYPE_STRING,       &game_speed_text,       ""                      },
-  { TYPE_SWITCH,       &setup.game_speed_extended, "Game Speed Extended List:" },
+  { TYPE_SWITCH,       &setup.team_mode,               "Team-Mode (Multi-Player):"     },
+  { TYPE_SWITCH,       &setup.network_mode,            "Network Multi-Player Mode:"    },
+  { TYPE_PLAYER,       &setup.network_player_nr,       "Preferred Network Player:"     },
+  { TYPE_TEXT_INPUT,   execGadgetNetworkServer,        "Network Server Hostname:"      },
+  { TYPE_STRING,       &network_server_text,           ""                              },
+  { TYPE_SWITCH,       &setup.use_api_server,          "Use Highscore Server:"         },
+  { TYPE_ENTER_LIST,   execSetupChooseScoresType,      "Scores in Highscore List:"     },
+  { TYPE_STRING,       &scores_type_text,              ""                              },
+  { TYPE_ENTER_LIST,   execOfferUploadTapes,           "Upload Tapes to Server"        },
+  { TYPE_SWITCH,       &setup.multiple_users,          "Multiple Users/Teams:"         },
+  { TYPE_YES_NO,       &setup.input_on_focus,          "Only Move Focussed Player:"    },
+  { TYPE_SWITCH,       &setup.time_limit,              "Time Limit:"                   },
 #if 1
-  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
-  { TYPE_STRING,       &scroll_delay_text,     ""                      },
+  { TYPE_YES_NO_ASK,   &setup.allow_skipping_levels,   "Allow Skipping Levels:"        },
+#else
+  { TYPE_SWITCH,       &setup.handicap,                "Force Solving Levels:"         },
+  { TYPE_SWITCH,       &setup.skip_levels,             "Allow Skipping Levels:"        },
 #endif
-  { TYPE_ENTER_LIST, execSetupChooseSnapshotMode,"Game Engine Snapshot Mode:" },
-  { TYPE_STRING,       &snapshot_mode_text,    ""                      },
-  { TYPE_SWITCH,       &setup.show_load_save_buttons,"Show Load/Save Buttons:" },
-  { TYPE_SWITCH,       &setup.show_undo_redo_buttons,"Show Undo/Redo Buttons:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_SWITCH,       &setup.increment_levels,        "Increment Solved Levels:"      },
+  { TYPE_SWITCH,       &setup.auto_play_next_level,    "Auto-play Next Level:"         },
+  { TYPE_SWITCH,       &setup.count_score_after_game,  "Count Score After Game:"       },
+  { TYPE_SWITCH,       &setup.show_scores_after_game,  "Show Scores After Game:"       },
+  { TYPE_YES_NO,       &setup.ask_on_game_over,        "Ask on Game Over:"             },
+  { TYPE_YES_NO,       &setup.ask_on_quit_game,        "Ask on Quit Game:"             },
+  { TYPE_YES_NO,       &setup.ask_on_quit_program,     "Ask on Quit Program:"          },
+  { TYPE_SWITCH,       &setup.autorecord,              "Auto-Record When Playing:"     },
+  { TYPE_SWITCH,       &setup.autorecord_after_replay, "Auto-Record After Replay:"     },
+  { TYPE_SWITCH,       &setup.auto_pause_on_start,     "Start Game in Pause Mode:"     },
+  { TYPE_ENTER_LIST,   execSetupChooseGameSpeed,       "Game Speed:"                   },
+  { TYPE_STRING,       &game_speed_text,               ""                              },
+  { TYPE_SWITCH,       &setup.game_speed_extended,     "Game Speed Extended List:"     },
+#if 1
+  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay,     "Scroll Delay:"                 },
+  { TYPE_STRING,       &scroll_delay_text,             ""                              },
+#endif
+  { TYPE_ENTER_LIST,   execSetupChooseSnapshotMode,    "Game Engine Snapshot Mode:"    },
+  { TYPE_STRING,       &snapshot_mode_text,            ""                              },
+  { TYPE_SWITCH,       &setup.show_load_save_buttons,  "Show Load/Save Buttons:"       },
+  { TYPE_SWITCH,       &setup.show_undo_redo_buttons,  "Show Undo/Redo Buttons:"       },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_engines[] =
 {
-  { TYPE_HEADLINE,     NULL,                   "Emerald Mine"          },
-  { TYPE_SWITCH,       &setup.forced_scroll_delay, "Scroll Delay:"     },
-  { TYPE_ECS_AGA,      &setup.prefer_aga_graphics, "Amiga Graphics Chipset:" },
-  { TYPE_SWITCH,       &setup.prefer_lowpass_sounds,"Low-Pass Filter Sounds:" },
-  { TYPE_SWITCH,       &setup.prefer_extra_panel_items,"Show Dynamite and Keys:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_HEADLINE,     NULL,                   "Supaplex"              },
-  { TYPE_SWITCH,       &setup.sp_show_border_elements, "Border Elements:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_LIST,   &execSetupChooseGameEngineType, "Default Game Engine:"          },
+  { TYPE_STRING,       &game_engine_type_text,         ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ECS_AGA,      &setup.prefer_aga_graphics,     "Game Graphics Style:"          },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_HEADLINE,     NULL,                           "Boulder Dash"                  },
+  { TYPE_SWITCH,       &setup.bd_skip_uncovering,      "Skip (un)covering screen:"     },
+  { 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_SWITCH,       &setup.bd_show_invisible_outbox,"Show invisible outbox:"        },
+  { TYPE_ENTER_LIST,   &execSetupChoosePaletteC64,     "Color Palette (C64):"          },
+  { TYPE_STRING,       &bd_palette_c64_text,           ""                              },
+  { TYPE_ENTER_LIST,   &execSetupChoosePaletteC64DTV,  "Color Palette (C64DTV):"       },
+  { TYPE_STRING,       &bd_palette_c64dtv_text,        ""                              },
+  { TYPE_ENTER_LIST,   &execSetupChoosePaletteAtari,   "Color Palette (Atari):"        },
+  { TYPE_STRING,       &bd_palette_atari_text,         ""                              },
+  { TYPE_ENTER_LIST,   &execSetupChooseColorType,      "Preferred Color Type:"         },
+  { TYPE_STRING,       &bd_color_type_text,            ""                              },
+  { TYPE_SWITCH,       &setup.bd_random_colors,        "Random Colors:"                },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_HEADLINE,     NULL,                           "Emerald Mine"                  },
+  { TYPE_SWITCH,       &setup.forced_scroll_delay,     "Scroll Delay:"                 },
+  { TYPE_SWITCH,       &setup.prefer_lowpass_sounds,   "Low-Pass Filter Sounds:"       },
+  { TYPE_SWITCH,       &setup.prefer_extra_panel_items,"Show Dynamite and Keys:"       },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_HEADLINE,     NULL,                           "Supaplex"                      },
+  { TYPE_SWITCH,       &setup.sp_show_border_elements, "Border Elements:"              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_editor[] =
 {
 #if 0
-  { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "Boulder Dash:" },
-  { TYPE_SWITCH,       &setup.editor.el_emerald_mine,  "Emerald Mine:" },
-  { TYPE_SWITCH, &setup.editor.el_emerald_mine_club,   "Emerald Mine Club:" },
-  { TYPE_SWITCH,       &setup.editor.el_more,          "Rocks'n'Diamonds:" },
-  { TYPE_SWITCH,       &setup.editor.el_sokoban,       "Sokoban:"      },
-  { TYPE_SWITCH,       &setup.editor.el_supaplex,      "Supaplex:"     },
-  { TYPE_SWITCH,       &setup.editor.el_diamond_caves, "Diamond Caves II:" },
-  { TYPE_SWITCH,       &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
-  { TYPE_SWITCH,       &setup.editor.el_chars,         "Text Characters:" },
-  { TYPE_SWITCH, &setup.editor.el_steel_chars, "Text Characters (Steel):" },
+  { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "Boulder Dash:"                 },
+  { TYPE_SWITCH,       &setup.editor.el_boulderdash_native, "Boulder Dash Native:"     },
+  { TYPE_SWITCH,       &setup.editor.el_emerald_mine,  "Emerald Mine:"                 },
+  { TYPE_SWITCH,       &setup.editor.el_emerald_mine_club, "Emerald Mine Club:"        },
+  { TYPE_SWITCH,       &setup.editor.el_more,          "Rocks'n'Diamonds:"             },
+  { TYPE_SWITCH,       &setup.editor.el_sokoban,       "Sokoban:"                      },
+  { TYPE_SWITCH,       &setup.editor.el_supaplex,      "Supaplex:"                     },
+  { TYPE_SWITCH,       &setup.editor.el_diamond_caves, "Diamond Caves II:"             },
+  { TYPE_SWITCH,       &setup.editor.el_dx_boulderdash,"DX-Boulderdash:"               },
+  { TYPE_SWITCH,       &setup.editor.el_chars,         "Text Characters:"              },
+  { TYPE_SWITCH,       &setup.editor.el_steel_chars,   "Text Characters (Steel):"      },
 #endif
-  { TYPE_SWITCH,       &setup.editor.el_classic,  "Classic Elements:" },
-  { TYPE_SWITCH,       &setup.editor.el_custom,  "Custom & Group Elements:" },
+  { TYPE_SWITCH,       &setup.editor.el_classic,       "Classic Elements:"             },
+  { TYPE_SWITCH,       &setup.editor.el_custom,        "Custom & Group Elements:"      },
 #if 0
-  { TYPE_SWITCH,       &setup.editor.el_headlines,     "Headlines:"    },
+  { TYPE_SWITCH,       &setup.editor.el_headlines,     "Headlines:"                    },
 #endif
-  { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
-  { TYPE_SWITCH,       &setup.editor.el_dynamic,  "Dynamic level elements:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
+  { TYPE_SWITCH, &setup.editor.el_user_defined,                "User defined element list:"    },
+  { TYPE_SWITCH,       &setup.editor.el_dynamic,       "Dynamic level elements:"       },
+  { TYPE_EMPTY,                NULL,                           ""                              },
 #if 0
-  { TYPE_SWITCH,       &setup.editor.el_by_game,   "Show elements by game:" },
-  { TYPE_SWITCH,       &setup.editor.el_by_type,   "Show elements by type:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
+  { TYPE_SWITCH,       &setup.editor.el_by_game,       "Show elements by game:"        },
+  { 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_EMPTY,                NULL,                   ""                      },
-  { TYPE_SWITCH, &setup.editor.show_read_only_warning, "Show read-only warning:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+  { TYPE_SWITCH, &setup.editor.show_element_token,     "Show element token:"           },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_SWITCH, &setup.editor.show_read_only_warning, "Show read-only warning:"       },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
 
-  { 0,                 NULL,                   NULL                    }
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_graphics[] =
 {
-#if !defined(PLATFORM_ANDROID)
-  { TYPE_SWITCH,       &setup.fullscreen,      "Fullscreen:"           },
-  { TYPE_ENTER_LIST,   execSetupChooseWindowSize, "Window Scaling:"    },
-  { TYPE_STRING,       &window_size_text,      ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseScalingType, "Anti-Aliasing:"    },
-  { TYPE_STRING,       &scaling_type_text,     ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseRenderingMode, "Special Rendering:" },
-  { TYPE_STRING,       &rendering_mode_text,   ""                      },
+#if !defined(PLATFORM_ANDROID) && !defined(PLATFORM_EMSCRIPTEN)
+  { TYPE_SWITCH,       &setup.fullscreen,              "Fullscreen:"                   },
+  { TYPE_ENTER_LIST,   execSetupChooseWindowSize,      "Window Scaling:"               },
+  { TYPE_STRING,       &window_size_text,              ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseScalingType,     "Anti-Aliasing:"                },
+  { TYPE_STRING,       &scaling_type_text,             ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseRenderingMode,   "Special Rendering:"            },
+  { TYPE_STRING,       &rendering_mode_text,           ""                              },
 #endif
 #if 0
-  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay, "Scroll Delay:"     },
-  { TYPE_STRING,       &scroll_delay_text,     ""                      },
+  { TYPE_ENTER_LIST,   execSetupChooseScrollDelay,     "Scroll Delay:"                 },
+  { TYPE_STRING,       &scroll_delay_text,             ""                              },
 #endif
-  { TYPE_ENTER_LIST,   execSetupChooseVsyncMode, "Vertical Sync (VSync):" },
-  { TYPE_STRING,       &vsync_mode_text,       ""                      },
-  { TYPE_SWITCH,       &setup.fade_screens,    "Fade Screens:"         },
-  { TYPE_SWITCH,       &setup.quick_switch,    "Quick Player Focus Switch:" },
-  { TYPE_SWITCH,       &setup.quick_doors,     "Quick Menu Doors:"     },
-  { TYPE_SWITCH,       &setup.show_titlescreen,"Show Title Screens:"   },
-  { TYPE_SWITCH,       &setup.toons,           "Show Menu Animations:" },
-  { TYPE_SWITCH,       &setup.small_game_graphics, "Small Game Graphics:" },
-  { TYPE_YES_NO_AUTO,  &setup.debug.xsn_mode,  debug_xsn_mode          },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+#if !defined(PLATFORM_EMSCRIPTEN)
+  { TYPE_ENTER_LIST,   execSetupChooseVsyncMode,       "Vertical Sync (VSync):"        },
+  { TYPE_STRING,       &vsync_mode_text,               ""                              },
+#endif
+  { TYPE_SWITCH,       &setup.fade_screens,            "Fade Screens:"                 },
+  { TYPE_SWITCH,       &setup.quick_switch,            "Quick Player Focus Switch:"    },
+  { TYPE_SWITCH,       &setup.quick_doors,             "Quick Menu Doors:"             },
+  { TYPE_SWITCH,       &setup.show_titlescreen,        "Show Title Screens:"           },
+  { TYPE_SWITCH,       &setup.toons,                   "Show Toons:"                   },
+  { TYPE_SWITCH,       &setup.small_game_graphics,     "Small Game Graphics:"          },
+  { TYPE_YES_NO_AUTO,  &setup.debug.xsn_mode,          debug_xsn_mode                  },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_sound[] =
 {
-  { TYPE_SWITCH,       &setup.sound_simple,    "Sound Effects (Normal):"  },
-  { TYPE_SWITCH,       &setup.sound_loops,     "Sound Effects (Looping):" },
-  { TYPE_SWITCH,       &setup.sound_music,     "Music:"                },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseVolumeSimple, "Sound Volume (Normal):" },
-  { TYPE_STRING,       &volume_simple_text,    ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseVolumeLoops, "Sound Volume (Looping):" },
-  { TYPE_STRING,       &volume_loops_text,     ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseVolumeMusic, "Music Volume:"     },
-  { TYPE_STRING,       &volume_music_text,     ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_SWITCH,       &setup.sound_simple,            "Sound Effects (Normal):"       },
+  { TYPE_SWITCH,       &setup.sound_loops,             "Sound Effects (Looping):"      },
+  { TYPE_SWITCH,       &setup.sound_music,             "Music:"                        },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseVolumeSimple,    "Sound Volume (Normal):"        },
+  { TYPE_STRING,       &volume_simple_text,            ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseVolumeLoops,     "Sound Volume (Looping):"       },
+  { TYPE_STRING,       &volume_loops_text,             ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseVolumeMusic,     "Music Volume:"                 },
+  { TYPE_STRING,       &volume_music_text,             ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_SWITCH,       &setup.audio_sample_rate_44100, "44100 Hz audio mixing:"        },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_artwork[] =
 {
-  { TYPE_ENTER_LIST,   execSetupChooseGraphics,"Custom Graphics:"      },
-  { TYPE_STRING,       &graphics_set_name,     ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseSounds,  "Custom Sounds:"        },
-  { TYPE_STRING,       &sounds_set_name,       ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseMusic,   "Custom Music:"         },
-  { TYPE_STRING,       &music_set_name,        ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_YES_NO_AUTO,&setup.override_level_graphics,"Override Level Graphics:"},
-  { TYPE_YES_NO_AUTO,&setup.override_level_sounds,  "Override Level Sounds:"  },
-  { TYPE_YES_NO_AUTO,&setup.override_level_music,   "Override Level Music:"   },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_LIST,   execSetupChooseGraphics,        "Custom Graphics:"              },
+  { TYPE_STRING,       &graphics_set_name,             ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseSounds,          "Custom Sounds:"                },
+  { TYPE_STRING,       &sounds_set_name,               ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseMusic,           "Custom Music:"                 },
+  { TYPE_STRING,       &music_set_name,                ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_YES_NO_AUTO,  &setup.override_level_graphics,"Override Level Graphics:"       },
+  { TYPE_YES_NO_AUTO,  &setup.override_level_sounds,   "Override Level Sounds:"        },
+  { TYPE_YES_NO_AUTO,  &setup.override_level_music,    "Override Level Music:"         },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_input[] =
 {
-  { TYPE_SWITCH,       NULL,                   "Player:"               },
-  { TYPE_SWITCH,       NULL,                   "Device:"               },
-  { TYPE_SWITCH,       NULL,                   ""                      },
-  { TYPE_SKIPPABLE,    NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_SKIPPABLE,    NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_SWITCH,       NULL,                           "Player:"                       },
+  { TYPE_SWITCH,       NULL,                           "Device:"                       },
+  { TYPE_SWITCH,       NULL,                           ""                              },
+  { TYPE_SKIPPABLE,    NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_SKIPPABLE,    NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_touch[] =
 {
-  { TYPE_ENTER_LIST,   execSetupChooseTouchControls, "Touch Control Type:" },
-  { TYPE_STRING,       &touch_controls_text,   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+  { TYPE_ENTER_LIST,   execSetupChooseTouchControls,   "Touch Control Type:"           },
+  { TYPE_STRING,       &touch_controls_text,           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
 
-  { 0,                 NULL,                   NULL                    }
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_touch_virtual_buttons_0[] =
 {
-  { TYPE_ENTER_LIST,   execSetupChooseTouchControls, "Touch Control Type:" },
-  { TYPE_STRING,       &touch_controls_text,   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseGridXSize_0, "Horizontal Buttons (Landscape):"   },
-  { TYPE_STRING,       &grid_size_text[0][0],  ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseGridYSize_0, "Vertical Buttons (Landscape):"     },
-  { TYPE_STRING,       &grid_size_text[0][1],  ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseTransparency, "Button Transparency:" },
-  { TYPE_STRING,       &transparency_text,     ""                      },
-  { TYPE_SWITCH,       &setup.touch.draw_outlined, "Draw Buttons Outlined:" },
-  { TYPE_SWITCH,       &setup.touch.draw_pressed, "Highlight Pressed Buttons:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_LIST,   execSetupChooseTouchControls,   "Touch Control Type:"           },
+  { TYPE_STRING,       &touch_controls_text,           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseGridXSize_0,     "Horizontal Buttons (Landscape):" },
+  { TYPE_STRING,       &grid_size_text[0][0],          ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseGridYSize_0,     "Vertical Buttons (Landscape):" },
+  { TYPE_STRING,       &grid_size_text[0][1],          ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseTransparency,    "Button Transparency:"          },
+  { TYPE_STRING,       &transparency_text,             ""                              },
+  { TYPE_SWITCH,       &setup.touch.draw_outlined,     "Draw Buttons Outlined:"        },
+  { TYPE_SWITCH,       &setup.touch.draw_pressed,      "Highlight Pressed Buttons:"    },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons"   },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_touch_virtual_buttons_1[] =
 {
-  { TYPE_ENTER_LIST,   execSetupChooseTouchControls, "Touch Control Type:" },
-  { TYPE_STRING,       &touch_controls_text,   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseGridXSize_1, "Horizontal Buttons (Portrait):"    },
-  { TYPE_STRING,       &grid_size_text[1][0],  ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseGridYSize_1, "Vertical Buttons (Portrait):"      },
-  { TYPE_STRING,       &grid_size_text[1][1],  ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseTransparency, "Button Transparency:" },
-  { TYPE_STRING,       &transparency_text,     ""                      },
-  { TYPE_SWITCH,       &setup.touch.draw_outlined, "Draw Buttons Outlined:" },
-  { TYPE_SWITCH,       &setup.touch.draw_pressed, "Highlight Pressed Buttons:" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_LIST,   execSetupChooseTouchControls,   "Touch Control Type:"           },
+  { TYPE_STRING,       &touch_controls_text,           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseGridXSize_1,     "Horizontal Buttons (Portrait):" },
+  { TYPE_STRING,       &grid_size_text[1][0],          ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseGridYSize_1,     "Vertical Buttons (Portrait):"  },
+  { TYPE_STRING,       &grid_size_text[1][1],          ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseTransparency,    "Button Transparency:"          },
+  { TYPE_STRING,       &transparency_text,             ""                              },
+  { TYPE_SWITCH,       &setup.touch.draw_outlined,     "Draw Buttons Outlined:"        },
+  { TYPE_SWITCH,       &setup.touch.draw_pressed,      "Highlight Pressed Buttons:"    },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons"   },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo *setup_info_touch_virtual_buttons[] =
@@ -7301,115 +8205,132 @@ static struct TokenInfo *setup_info_touch_virtual_buttons[] =
 
 static struct TokenInfo setup_info_touch_wipe_gestures[] =
 {
-  { TYPE_ENTER_LIST,   execSetupChooseTouchControls, "Touch Control Type:" },
-  { TYPE_STRING,       &touch_controls_text,   ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseMoveDistance, "Move Trigger Distance:" },
-  { TYPE_STRING,       &move_distance_text,    ""                      },
-  { TYPE_ENTER_LIST,   execSetupChooseDropDistance, "Drop Trigger Distance:" },
-  { TYPE_STRING,       &drop_distance_text,    ""                      },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_ENTER_LIST,   execSetupChooseTouchControls,   "Touch Control Type:"           },
+  { TYPE_STRING,       &touch_controls_text,           ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseMoveDistance,    "Move Trigger Distance:"        },
+  { TYPE_STRING,       &move_distance_text,            ""                              },
+  { TYPE_ENTER_LIST,   execSetupChooseDropDistance,    "Drop Trigger Distance:"        },
+  { TYPE_STRING,       &drop_distance_text,            ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts[] =
 {
-  { TYPE_ENTER_MENU,   execSetupShortcuts1,    "Various Keys"          },
-  { TYPE_ENTER_MENU,   execSetupShortcuts2,    "Player Focus"          },
-  { TYPE_ENTER_MENU,   execSetupShortcuts3,    "Tape Buttons"          },
-  { TYPE_ENTER_MENU,   execSetupShortcuts4,    "Sound & Music"         },
-  { TYPE_ENTER_MENU,   execSetupShortcuts5,    "TAS Snap Keys"         },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+  { TYPE_ENTER_MENU,   execSetupShortcuts1,            "Various Keys"                  },
+  { TYPE_ENTER_MENU,   execSetupShortcuts2,            "Player Focus"                  },
+  { TYPE_ENTER_MENU,   execSetupShortcuts3,            "Tape Buttons"                  },
+  { TYPE_ENTER_MENU,   execSetupShortcuts4,            "Sound & Music"                 },
+  { TYPE_ENTER_MENU,   execSetupShortcuts5,            "TAS Snap Keys"                 },
+  { TYPE_ENTER_MENU,   execSetupShortcuts6,            "Speed Keys"                    },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupMain,                  "Back"                          },
 
-  { 0,                 NULL,                   NULL                    }
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts_1[] =
 {
-  { TYPE_KEYTEXT,      NULL,           "Quick Save Game to Tape:",     },
-  { TYPE_KEY,          &setup.shortcut.save_game, ""                   },
-  { TYPE_KEYTEXT,      NULL,           "Quick Load Game from Tape:",   },
-  { TYPE_KEY,          &setup.shortcut.load_game, ""                   },
-  { TYPE_KEYTEXT,      NULL,           "Start Game & Toggle Pause:",   },
-  { TYPE_KEY,          &setup.shortcut.toggle_pause, ""                },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_YES_NO,       &setup.ask_on_escape,   "Ask on 'Esc' Key:"     },
-  { TYPE_YES_NO, &setup.ask_on_escape_editor,  "Ask on 'Esc' Key (Editor):" },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupShortcuts,     "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_KEYTEXT,      NULL,                           "Quick Save Game to Tape:"      },
+  { TYPE_KEY,          &setup.shortcut.save_game,      ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Quick Load Game from Tape:"    },
+  { TYPE_KEY,          &setup.shortcut.load_game,      ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Restart Game:"                 },
+  { TYPE_KEY,          &setup.shortcut.restart_game,   ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Replay & Pause Before End:"    },
+  { TYPE_KEY,          &setup.shortcut.pause_before_end, ""                            },
+  { TYPE_KEYTEXT,      NULL,                           "Start Game & Toggle Pause:"    },
+  { TYPE_KEY,          &setup.shortcut.toggle_pause,   ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_YES_NO,       &setup.ask_on_escape,           "Ask on 'Esc' Key:"             },
+  { TYPE_YES_NO, &setup.ask_on_escape_editor,          "Ask on 'Esc' Key (Editor):"    },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts_2[] =
 {
-  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 1:",       },
-  { TYPE_KEY,          &setup.shortcut.focus_player[0], ""             },
-  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 2:",       },
-  { TYPE_KEY,          &setup.shortcut.focus_player[1], ""             },
-  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 3:",       },
-  { TYPE_KEY,          &setup.shortcut.focus_player[2], ""             },
-  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 4:",       },
-  { TYPE_KEY,          &setup.shortcut.focus_player[3], ""             },
-  { TYPE_KEYTEXT,      NULL,           "Set Focus to All Players:",    },
-  { TYPE_KEY,          &setup.shortcut.focus_player_all, ""            },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupShortcuts,     "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_KEYTEXT,      NULL,                           "Set Focus to Player 1:"        },
+  { TYPE_KEY,          &setup.shortcut.focus_player[0], ""                             },
+  { TYPE_KEYTEXT,      NULL,                           "Set Focus to Player 2:"        },
+  { TYPE_KEY,          &setup.shortcut.focus_player[1], ""                             },
+  { TYPE_KEYTEXT,      NULL,                           "Set Focus to Player 3:"        },
+  { TYPE_KEY,          &setup.shortcut.focus_player[2], ""                             },
+  { TYPE_KEYTEXT,      NULL,                           "Set Focus to Player 4:"        },
+  { TYPE_KEY,          &setup.shortcut.focus_player[3], ""                             },
+  { TYPE_KEYTEXT,      NULL,                           "Set Focus to All Players:"     },
+  { TYPE_KEY,          &setup.shortcut.focus_player_all, ""                            },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts_3[] =
 {
-  { TYPE_KEYTEXT,      NULL,                   "Eject Tape:",          },
-  { TYPE_KEY,          &setup.shortcut.tape_eject, ""                  },
-  { TYPE_KEYTEXT,      NULL,                   "Warp / Single Step:",  },
-  { TYPE_KEY,          &setup.shortcut.tape_extra, ""                  },
-  { TYPE_KEYTEXT,      NULL,                   "Stop Tape:",           },
-  { TYPE_KEY,          &setup.shortcut.tape_stop, ""                   },
-  { TYPE_KEYTEXT,      NULL,                   "Pause / Unpause Tape:",},
-  { TYPE_KEY,          &setup.shortcut.tape_pause, ""                  },
-  { TYPE_KEYTEXT,      NULL,                   "Record Tape:",         },
-  { TYPE_KEY,          &setup.shortcut.tape_record, ""                 },
-  { TYPE_KEYTEXT,      NULL,                   "Play Tape:",           },
-  { TYPE_KEY,          &setup.shortcut.tape_play, ""                   },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupShortcuts,     "Back"                  },
-
-  { 0,                 NULL,                   NULL                    }
+  { TYPE_KEYTEXT,      NULL,                           "Eject Tape:"                   },
+  { TYPE_KEY,          &setup.shortcut.tape_eject,     ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Warp / Single Step:"           },
+  { TYPE_KEY,          &setup.shortcut.tape_extra,     ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Stop Tape:"                    },
+  { TYPE_KEY,          &setup.shortcut.tape_stop,      ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Pause / Unpause Tape:"         },
+  { TYPE_KEY,          &setup.shortcut.tape_pause,     ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Record Tape:"                  },
+  { TYPE_KEY,          &setup.shortcut.tape_record,    ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Play Tape:"                    },
+  { TYPE_KEY,          &setup.shortcut.tape_play,      ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts_4[] =
 {
-  { TYPE_KEYTEXT,      NULL,           "Toggle Sound Effects (Normal):", },
-  { TYPE_KEY,          &setup.shortcut.sound_simple, ""                },
-  { TYPE_KEYTEXT,      NULL,           "Toggle Sound Effects (Looping):", },
-  { TYPE_KEY,          &setup.shortcut.sound_loops, ""                 },
-  { TYPE_KEYTEXT,      NULL,           "Toggle Music:",                },
-  { TYPE_KEY,          &setup.shortcut.sound_music, ""                 },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupShortcuts,     "Back"                  },
+  { TYPE_KEYTEXT,      NULL,                           "Toggle Sound Effects (Normal):" },
+  { TYPE_KEY,          &setup.shortcut.sound_simple,   ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Toggle Sound Effects (Looping):" },
+  { TYPE_KEY,          &setup.shortcut.sound_loops,    ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Toggle Music:"                 },
+  { TYPE_KEY,          &setup.shortcut.sound_music,    ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
 
-  { 0,                 NULL,                   NULL                    }
+  { 0,                 NULL,                           NULL                            }
 };
 
 static struct TokenInfo setup_info_shortcuts_5[] =
 {
-  { TYPE_KEYTEXT,      NULL,                   "Snap Left:",           },
-  { TYPE_KEY,          &setup.shortcut.snap_left, ""                   },
-  { TYPE_KEYTEXT,      NULL,                   "Snap Right:",          },
-  { TYPE_KEY,          &setup.shortcut.snap_right, ""                  },
-  { TYPE_KEYTEXT,      NULL,                   "Snap Up:",             },
-  { TYPE_KEY,          &setup.shortcut.snap_up, ""                     },
-  { TYPE_KEYTEXT,      NULL,                   "Snap Down:",           },
-  { TYPE_KEY,          &setup.shortcut.snap_down, ""                   },
-  { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupShortcuts,     "Back"                  },
+  { TYPE_KEYTEXT,      NULL,                           "Snap Left:"                    },
+  { TYPE_KEY,          &setup.shortcut.snap_left,      ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Snap Right:"                   },
+  { TYPE_KEY,          &setup.shortcut.snap_right,     ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Snap Up:"                      },
+  { TYPE_KEY,          &setup.shortcut.snap_up,        ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Snap Down:"                    },
+  { TYPE_KEY,          &setup.shortcut.snap_down,      ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
+};
 
-  { 0,                 NULL,                   NULL                    }
+static struct TokenInfo setup_info_shortcuts_6[] =
+{
+  { TYPE_KEYTEXT,      NULL,                           "Fast Playing Speed:"           },
+  { TYPE_KEY,          &setup.shortcut.speed_fast,     ""                              },
+  { TYPE_KEYTEXT,      NULL,                           "Slow Playing Speed:"           },
+  { TYPE_KEY,          &setup.shortcut.speed_slow,     ""                              },
+  { TYPE_EMPTY,                NULL,                           ""                              },
+  { TYPE_LEAVE_MENU,   execSetupShortcuts,             "Back"                          },
+
+  { 0,                 NULL,                           NULL                            }
 };
 
 static Key getSetupKey(void)
@@ -7427,7 +8348,7 @@ static Key getSetupKey(void)
       {
         case EVENT_KEYPRESS:
          {
-           key = GetEventKey((KeyEvent *)&event, TRUE);
+           key = GetEventKey((KeyEvent *)&event);
 
            // press 'Escape' or 'Enter' to keep the existing key binding
            if (key == KSYM_Escape || key == KSYM_Return)
@@ -7466,8 +8387,11 @@ static int getSetupValueFont(int type, void *value)
   else if (type & TYPE_BOOLEAN_STYLE)
     return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
   else if (type & TYPE_YES_NO_AUTO)
-    return (*(int *)value == AUTO  ? FONT_OPTION_ON :
-           *(int *)value == FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON);
+    return (*(int *)value == STATE_AUTO  ? FONT_OPTION_ON :
+           *(int *)value == STATE_FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON);
+  else if (type & TYPE_YES_NO_ASK)
+    return (*(int *)value == STATE_ASK   ? FONT_OPTION_ON :
+           *(int *)value == STATE_FALSE ? FONT_OPTION_OFF : FONT_OPTION_ON);
   else if (type & TYPE_PLAYER)
     return FONT_VALUE_1;
   else
@@ -7488,10 +8412,11 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
   struct TokenInfo *si = &setup_info[si_pos];
   boolean font_draw_xoffset_modified = FALSE;
   boolean scrollbar_needed = (num_setup_info < max_setup_info);
+  int mx_scrollbar = screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x;
+  int mx_right_border = (scrollbar_needed ? mx_scrollbar : SX + SXSIZE);
   int font_draw_xoffset_old = -1;
-  int xoffset = (scrollbar_needed ? -1 : 0);
+  int xoffset = (scrollbar_needed ? 0 : 1);
   int menu_screen_value_xpos = MENU_SCREEN_VALUE_XPOS + xoffset;
-  int menu_screen_max_xpos = MENU_SCREEN_MAX_XPOS + xoffset;
   int xpos = menu_screen_value_xpos;
   int ypos = MENU_SCREEN_START_YPOS + screen_pos;
   int startx = mSX + xpos * 32;
@@ -7502,7 +8427,6 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
   int font_nr_default = getSetupValueFont(type, value);
   int font_width_default = getFontWidth(font_nr_default);
   int font_nr = font_nr_default;
-  int i;
 
   if (value_string == NULL)
     return;
@@ -7523,10 +8447,6 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
     if (strlen(value_string) > max_value_len)
       value_string[max_value_len] = '\0';
   }
-  else if (type & TYPE_YES_NO_AUTO)
-  {
-    xpos = menu_screen_value_xpos - 1;
-  }
   else if (type & TYPE_PLAYER)
   {
     int displayed_player_nr = *(int *)value + 1;
@@ -7537,28 +8457,9 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
   startx = mSX + xpos * 32;
   starty = mSY + ypos * 32;
 
-  // special check if right-side setup values moved left due to scrollbar
-  if (scrollbar_needed && xpos > MENU_SCREEN_START_XPOS)
-  {
-    int max_menu_text_length = 26;     // maximum text length for classic menu
-    int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
-    int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
-    int text_font_nr = getMenuTextFont(FONT_MENU_2);
-    int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
-    int text_width = max_menu_text_length * getFontWidth(text_font_nr);
-
-    if (startx + font_xoffset < text_startx + text_width + text_font_xoffset)
-    {
-      // when using narrow font, left-shifting text "auto" not needed
-      if (type & TYPE_YES_NO_AUTO)
-       xpos += 1;
-
-      xpos += 1;
-      startx = mSX + xpos * 32;
-
-      font_nr = getSetupValueFontNarrow(type, font_nr);
-    }
-  }
+  // always use narrow font for setup values on right screen side
+  if (xpos > MENU_SCREEN_START_XPOS)
+    font_nr = getSetupValueFontNarrow(type, font_nr);
 
   // downward compatibility correction for Juergen Bonhagen's menu settings
   if (setup_mode != SETUP_MODE_INPUT)
@@ -7567,11 +8468,11 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
                                    MENU_SCREEN_START_XPOS);
     int max_menu_text_length_medium = max_menu_text_length_big * 2;
     int check_font_nr = FONT_OPTION_ON; // known font that needs correction
-    int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
-    int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
+    int font1_xoffset = getFontDrawOffsetX(font_nr);
+    int font2_xoffset = getFontDrawOffsetX(check_font_nr);
     int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
     int text_font_nr = getMenuTextFont(FONT_MENU_2);
-    int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
+    int text_font_xoffset = getFontDrawOffsetX(text_font_nr);
     int text_width = max_menu_text_length_medium * getFontWidth(text_font_nr);
     boolean correct_font_draw_xoffset = FALSE;
 
@@ -7587,7 +8488,7 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
     // (this can happen for extreme/wrong values for font draw offset)
     if (correct_font_draw_xoffset)
     {
-      font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
+      font_draw_xoffset_old = getFontDrawOffsetX(font_nr);
       font_draw_xoffset_modified = TRUE;
 
       if (type & TYPE_KEY)
@@ -7598,9 +8499,7 @@ static void drawSetupValue(int screen_pos, int setup_info_pos_raw)
     }
   }
 
-  for (i = 0; i <= menu_screen_max_xpos - xpos; i++)
-    DrawText(startx + i * font_width_default, starty, " ", font_nr_default);
-
+  DrawBackground(startx, starty, mx_right_border - startx, getFontHeight(font_nr));
   DrawText(startx, starty, value_string, font_nr);
 
   if (type & TYPE_PLAYER)
@@ -7636,10 +8535,19 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
   {
     *(int *)si->value =
       (dx == -1 ?
-       (*(int *)si->value == AUTO ? TRUE :
-       *(int *)si->value == TRUE ? FALSE : AUTO) :
-       (*(int *)si->value == TRUE ? AUTO :
-       *(int *)si->value == AUTO ? FALSE : TRUE));
+       (*(int *)si->value == STATE_AUTO ? STATE_TRUE :
+       *(int *)si->value == STATE_TRUE ? STATE_FALSE : STATE_AUTO) :
+       (*(int *)si->value == STATE_TRUE ? STATE_AUTO :
+       *(int *)si->value == STATE_AUTO ? STATE_FALSE : STATE_TRUE));
+  }
+  else if (si->type & TYPE_YES_NO_ASK)
+  {
+    *(int *)si->value =
+      (dx == -1 ?
+       (*(int *)si->value == STATE_ASK  ? STATE_TRUE :
+       *(int *)si->value == STATE_TRUE ? STATE_FALSE : STATE_ASK) :
+       (*(int *)si->value == STATE_TRUE ? STATE_ASK :
+       *(int *)si->value == STATE_ASK  ? STATE_FALSE : STATE_TRUE));
   }
   else if (si->type & TYPE_KEY)
   {
@@ -7671,13 +8579,17 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
   if (si->value == &setup.fullscreen)
     ToggleFullscreenIfNeeded();
 
+  // audio sample rate may have changed at this point
+  if (si->value == &setup.audio_sample_rate_44100)
+    ToggleAudioSampleRateIfNeeded();
+
   // network mode may have changed at this point
   if (si->value == &setup.network_mode)
     ToggleNetworkModeIfNeeded();
 
   // API server mode may have changed at this point
   if (si->value == &setup.use_api_server)
-    runtime.use_api_server = setup.use_api_server;
+    ToggleUseApiServerIfNeeded();
 
   // game speed list may have changed at this point
   if (si->value == &setup.game_speed_extended)
@@ -7821,6 +8733,11 @@ static void DrawSetupScreen_Generic(void)
     setup_info = setup_info_shortcuts_5;
     title_string = STR_SETUP_SHORTCUTS;
   }
+  else if (setup_mode == SETUP_MODE_SHORTCUTS_6)
+  {
+    setup_info = setup_info_shortcuts_6;
+    title_string = STR_SETUP_SHORTCUTS;
+  }
 
   // use modified setup info without setup entries marked as hidden
   setup_info = getSetupInfoFinal(setup_info);
@@ -8213,14 +9130,18 @@ static boolean CustomizeKeyboardMain(int player_nr)
   while (!finished)
   {
     Event event;
+    DelayCounter event_frame_delay = { GAME_FRAME_DELAY };
 
-    if (NextValidEvent(&event))
+    // reset frame delay counter directly after updating screen
+    ResetDelayCounter(&event_frame_delay);
+
+    while (NextValidEvent(&event))
     {
       switch (event.type)
       {
         case EVENT_KEYPRESS:
          {
-           Key key = GetEventKey((KeyEvent *)&event, FALSE);
+           Key key = GetEventKey((KeyEvent *)&event);
 
            // press 'Escape' to abort and keep the old key bindings
            if (key == KSYM_Escape)
@@ -8285,6 +9206,10 @@ static boolean CustomizeKeyboardMain(int player_nr)
          HandleOtherEvents(&event);
          break;
       }
+
+      // do not handle events for longer than standard frame delay period
+      if (DelayReached(&event_frame_delay))
+       break;
     }
 
     BackToFront();
@@ -8307,8 +9232,7 @@ void CustomizeKeyboard(int player_nr)
     int font_height = getFontHeight(font_nr);
     int ypos1 = SYSIZE / 2 - font_height * 2;
     int ypos2 = SYSIZE / 2 - font_height * 1;
-    unsigned int wait_frame_delay = 0;
-    unsigned int wait_frame_delay_value = 2000;
+    DelayCounter wait_frame_delay = { 2000 };
 
     ResetDelayCounter(&wait_frame_delay);
 
@@ -8317,7 +9241,7 @@ void CustomizeKeyboard(int player_nr)
     DrawTextSCentered(ypos1, font_nr, "Keyboard");
     DrawTextSCentered(ypos2, font_nr, "configured!");
 
-    while (!DelayReached(&wait_frame_delay, wait_frame_delay_value))
+    while (!DelayReached(&wait_frame_delay))
       BackToFront();
 
     ClearEventQueue();
@@ -8387,11 +9311,6 @@ static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick)
     { 282, 210, MARKER_AXIS_Y, "righty",       },
   };
 
-  unsigned int event_frame_delay = 0;
-  unsigned int event_frame_delay_value = GAME_FRAME_DELAY;
-
-  ResetDelayCounter(&event_frame_delay);
-
   if (!bitmaps_initialized)
   {
     controller = LoadCustomImage("joystick/controller.png");
@@ -8523,6 +9442,11 @@ static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick)
 
       screen_initialized = TRUE;
 
+      DelayCounter event_frame_delay = { GAME_FRAME_DELAY };
+
+      // reset frame delay counter directly after updating screen
+      ResetDelayCounter(&event_frame_delay);
+
       while (NextValidEvent(&event))
       {
        switch (event.type)
@@ -8656,7 +9580,7 @@ static boolean ConfigureJoystickMapButtonsAndAxes(SDL_Joystick *joystick)
        }
 
        // do not handle events for longer than standard frame delay period
-       if (DelayReached(&event_frame_delay, event_frame_delay_value))
+       if (DelayReached(&event_frame_delay))
          break;
       }
     }
@@ -8740,8 +9664,7 @@ void ConfigureJoystick(int player_nr)
     int font_height = getFontHeight(font_nr);
     int ypos1 = SYSIZE / 2 - font_height * 2;
     int ypos2 = SYSIZE / 2 - font_height * 1;
-    unsigned int wait_frame_delay = 0;
-    unsigned int wait_frame_delay_value = 2000;
+    DelayCounter wait_frame_delay = { 2000 };
 
     ResetDelayCounter(&wait_frame_delay);
 
@@ -8752,7 +9675,7 @@ void ConfigureJoystick(int player_nr)
     DrawTextSCentered(ypos1, font_nr, message1);
     DrawTextSCentered(ypos2, font_nr, message2);
 
-    while (!DelayReached(&wait_frame_delay, wait_frame_delay_value))
+    while (!DelayReached(&wait_frame_delay))
       BackToFront();
 
     ClearEventQueue();
@@ -8869,7 +9792,7 @@ static boolean ConfigureVirtualButtonsMain(void)
 
         case EVENT_KEYPRESS:
          {
-           Key key = GetEventKey((KeyEvent *)&event, FALSE);
+           Key key = GetEventKey((KeyEvent *)&event);
 
            action = (key == KSYM_Escape ?      ACTION_ESCAPE :
                      key == KSYM_BackSpace ||
@@ -9070,8 +9993,7 @@ void ConfigureVirtualButtons(void)
     int font_height = getFontHeight(font_nr);
     int ypos1 = SYSIZE / 2 - font_height * 2;
     int ypos2 = SYSIZE / 2 - font_height * 1;
-    unsigned int wait_frame_delay = 0;
-    unsigned int wait_frame_delay_value = 2000;
+    DelayCounter wait_frame_delay = { 2000 };
 
     ResetDelayCounter(&wait_frame_delay);
 
@@ -9080,7 +10002,7 @@ void ConfigureVirtualButtons(void)
     DrawTextSCentered(ypos1, font_nr, "Virtual buttons");
     DrawTextSCentered(ypos2, font_nr, "configured!");
 
-    while (!DelayReached(&wait_frame_delay, wait_frame_delay_value))
+    while (!DelayReached(&wait_frame_delay))
       BackToFront();
 
     ClearEventQueue();
@@ -9102,6 +10024,16 @@ void DrawSetupScreen(void)
     DrawChooseTree(&scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
     DrawChooseTree(&snapshot_mode_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE)
+    DrawChooseTree(&game_engine_type_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64)
+    DrawChooseTree(&bd_palette_c64_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV)
+    DrawChooseTree(&bd_palette_c64dtv_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_ATARI)
+    DrawChooseTree(&bd_palette_atari_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_COLOR_TYPE)
+    DrawChooseTree(&bd_color_type_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     DrawChooseTree(&window_size_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
@@ -9186,6 +10118,16 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
     HandleChooseTree(mx, my, dx, dy, button, &scroll_delay_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SNAPSHOT_MODE)
     HandleChooseTree(mx, my, dx, dy, button, &snapshot_mode_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_GAME_ENGINE_TYPE)
+    HandleChooseTree(mx, my, dx, dy, button, &game_engine_type_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64)
+    HandleChooseTree(mx, my, dx, dy, button, &bd_palette_c64_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_C64DTV)
+    HandleChooseTree(mx, my, dx, dy, button, &bd_palette_c64dtv_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_PALETTE_ATARI)
+    HandleChooseTree(mx, my, dx, dy, button, &bd_palette_atari_current);
+  else if (setup_mode == SETUP_MODE_CHOOSE_BD_COLOR_TYPE)
+    HandleChooseTree(mx, my, dx, dy, button, &bd_color_type_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_WINDOW_SIZE)
     HandleChooseTree(mx, my, dx, dy, button, &window_size_current);
   else if (setup_mode == SETUP_MODE_CHOOSE_SCALING_TYPE)
@@ -9228,15 +10170,8 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
 
 void HandleGameActions(void)
 {
-  if (setup.ask_on_game_over)
-    CheckGameOver();
-
-  if (game.restart_game_message != NULL)
-  {
-    RequestRestartGame(game.restart_game_message);
-
+  if (CheckRestartGame())
     return;
-  }
 
   if (game_status != GAME_MODE_PLAYING)
     return;
@@ -9252,7 +10187,7 @@ void HandleGameActions(void)
 
 static struct
 {
-  int gfx_unpressed, gfx_pressed;
+  int gfx_unpressed, gfx_pressed, gfx_active;
   struct MenuPosInfo *pos;
   boolean *check_value;
   int gadget_id;
@@ -9263,7 +10198,7 @@ static struct
 } menubutton_info[NUM_SCREEN_MENUBUTTONS] =
 {
   {
-    IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE,
+    IMG_MENU_BUTTON_PREV_LEVEL, IMG_MENU_BUTTON_PREV_LEVEL_ACTIVE, -1,
     &menu.main.button.prev_level, NULL,
     SCREEN_CTRL_ID_PREV_LEVEL,
     SCREEN_MASK_MAIN,
@@ -9271,7 +10206,7 @@ static struct
     FALSE, "previous level"
   },
   {
-    IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE,
+    IMG_MENU_BUTTON_NEXT_LEVEL, IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE, -1,
     &menu.main.button.next_level, NULL,
     SCREEN_CTRL_ID_NEXT_LEVEL,
     SCREEN_MASK_MAIN,
@@ -9279,7 +10214,47 @@ static struct
     FALSE, "next level"
   },
   {
-    IMG_MENU_BUTTON_FIRST_LEVEL, IMG_MENU_BUTTON_FIRST_LEVEL_ACTIVE,
+    IMG_MENU_BUTTON_PREV_LEVEL2, IMG_MENU_BUTTON_PREV_LEVEL2_ACTIVE, -1,
+    &menu.scores.button.prev_level, NULL,
+    SCREEN_CTRL_ID_PREV_LEVEL2,
+    SCREEN_MASK_SCORES | SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "previous level"
+  },
+  {
+    IMG_MENU_BUTTON_NEXT_LEVEL2, IMG_MENU_BUTTON_NEXT_LEVEL2_ACTIVE, -1,
+    &menu.scores.button.next_level, NULL,
+    SCREEN_CTRL_ID_NEXT_LEVEL2,
+    SCREEN_MASK_SCORES | SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "next level"
+  },
+  {
+    IMG_MENU_BUTTON_PREV_SCORE, IMG_MENU_BUTTON_PREV_SCORE_ACTIVE, -1,
+    &menu.scores.button.prev_score, NULL,
+    SCREEN_CTRL_ID_PREV_SCORE,
+    SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "previous score"
+  },
+  {
+    IMG_MENU_BUTTON_NEXT_SCORE, IMG_MENU_BUTTON_NEXT_SCORE_ACTIVE, -1,
+    &menu.scores.button.next_score, NULL,
+    SCREEN_CTRL_ID_NEXT_SCORE,
+    SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_PRESSED | GD_EVENT_REPEATED,
+    FALSE, "next score"
+  },
+  {
+    IMG_MENU_BUTTON_PLAY_TAPE, IMG_MENU_BUTTON_PLAY_TAPE, -1,
+    &menu.scores.button.play_tape, NULL,
+    SCREEN_CTRL_ID_PLAY_TAPE,
+    SCREEN_MASK_SCORES_INFO,
+    GD_EVENT_RELEASED,
+    FALSE, "play tape"
+  },
+  {
+    IMG_MENU_BUTTON_FIRST_LEVEL, IMG_MENU_BUTTON_FIRST_LEVEL_ACTIVE, -1,
     &menu.main.button.first_level, NULL,
     SCREEN_CTRL_ID_FIRST_LEVEL,
     SCREEN_MASK_MAIN,
@@ -9287,7 +10262,7 @@ static struct
     FALSE, "first level"
   },
   {
-    IMG_MENU_BUTTON_LAST_LEVEL, IMG_MENU_BUTTON_LAST_LEVEL_ACTIVE,
+    IMG_MENU_BUTTON_LAST_LEVEL, IMG_MENU_BUTTON_LAST_LEVEL_ACTIVE, -1,
     &menu.main.button.last_level, NULL,
     SCREEN_CTRL_ID_LAST_LEVEL,
     SCREEN_MASK_MAIN,
@@ -9295,7 +10270,7 @@ static struct
     FALSE, "last level"
   },
   {
-    IMG_MENU_BUTTON_LEVEL_NUMBER, IMG_MENU_BUTTON_LEVEL_NUMBER_ACTIVE,
+    IMG_MENU_BUTTON_LEVEL_NUMBER, IMG_MENU_BUTTON_LEVEL_NUMBER_ACTIVE, -1,
     &menu.main.button.level_number, NULL,
     SCREEN_CTRL_ID_LEVEL_NUMBER,
     SCREEN_MASK_MAIN,
@@ -9303,7 +10278,7 @@ static struct
     FALSE, "level number"
   },
   {
-    IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE,
+    IMG_MENU_BUTTON_LEFT, IMG_MENU_BUTTON_LEFT_ACTIVE, -1,
     &menu.setup.button.prev_player, NULL,
     SCREEN_CTRL_ID_PREV_PLAYER,
     SCREEN_MASK_INPUT,
@@ -9311,7 +10286,7 @@ static struct
     FALSE, "previous player"
   },
   {
-    IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE,
+    IMG_MENU_BUTTON_RIGHT, IMG_MENU_BUTTON_RIGHT_ACTIVE, -1,
     &menu.setup.button.next_player, NULL,
     SCREEN_CTRL_ID_NEXT_PLAYER,
     SCREEN_MASK_INPUT,
@@ -9319,7 +10294,7 @@ static struct
     FALSE, "next player"
   },
   {
-    IMG_MENU_BUTTON_INSERT_SOLUTION, IMG_MENU_BUTTON_INSERT_SOLUTION_ACTIVE,
+    IMG_MENU_BUTTON_INSERT_SOLUTION, IMG_MENU_BUTTON_INSERT_SOLUTION_ACTIVE, -1,
     &menu.main.button.insert_solution, NULL,
     SCREEN_CTRL_ID_INSERT_SOLUTION,
     SCREEN_MASK_MAIN_HAS_SOLUTION,
@@ -9327,7 +10302,7 @@ static struct
     FALSE, "insert solution tape"
   },
   {
-    IMG_MENU_BUTTON_PLAY_SOLUTION, IMG_MENU_BUTTON_PLAY_SOLUTION_ACTIVE,
+    IMG_MENU_BUTTON_PLAY_SOLUTION, IMG_MENU_BUTTON_PLAY_SOLUTION_ACTIVE, -1,
     &menu.main.button.play_solution, NULL,
     SCREEN_CTRL_ID_PLAY_SOLUTION,
     SCREEN_MASK_MAIN_HAS_SOLUTION,
@@ -9335,15 +10310,24 @@ static struct
     FALSE, "play solution tape"
   },
   {
-    IMG_MENU_BUTTON_SWITCH_ECS_AGA, IMG_MENU_BUTTON_SWITCH_ECS_AGA_ACTIVE,
+    IMG_MENU_BUTTON_LEVELSET_INFO, IMG_MENU_BUTTON_LEVELSET_INFO_PRESSED,
+    IMG_MENU_BUTTON_LEVELSET_INFO_ACTIVE,
+    &menu.main.button.levelset_info, NULL,
+    SCREEN_CTRL_ID_LEVELSET_INFO,
+    SCREEN_MASK_MAIN_HAS_SET_INFO,
+    GD_EVENT_RELEASED,
+    FALSE, "show level set info"
+  },
+  {
+    IMG_MENU_BUTTON_SWITCH_ECS_AGA, IMG_MENU_BUTTON_SWITCH_ECS_AGA_ACTIVE, -1,
     &menu.main.button.switch_ecs_aga, &setup.prefer_aga_graphics,
     SCREEN_CTRL_ID_SWITCH_ECS_AGA,
     SCREEN_MASK_MAIN,
     GD_EVENT_RELEASED | GD_EVENT_OFF_BORDERS,
-    FALSE, "switch ECS/AGA chipset"
+    FALSE, "switch old/new graphics"
   },
   {
-    IMG_MENU_BUTTON_TOUCH_BACK, IMG_MENU_BUTTON_TOUCH_BACK,
+    IMG_MENU_BUTTON_TOUCH_BACK, IMG_MENU_BUTTON_TOUCH_BACK, -1,
     &menu.setup.button.touch_back, NULL,
     SCREEN_CTRL_ID_TOUCH_PREV_PAGE,
     SCREEN_MASK_TOUCH,
@@ -9351,7 +10335,7 @@ static struct
     TRUE, "previous page"
   },
   {
-    IMG_MENU_BUTTON_TOUCH_NEXT, IMG_MENU_BUTTON_TOUCH_NEXT,
+    IMG_MENU_BUTTON_TOUCH_NEXT, IMG_MENU_BUTTON_TOUCH_NEXT, -1,
     &menu.setup.button.touch_next, NULL,
     SCREEN_CTRL_ID_TOUCH_NEXT_PAGE,
     SCREEN_MASK_TOUCH,
@@ -9359,7 +10343,7 @@ static struct
     TRUE, "next page"
   },
   {
-    IMG_MENU_BUTTON_TOUCH_BACK2, IMG_MENU_BUTTON_TOUCH_BACK2,
+    IMG_MENU_BUTTON_TOUCH_BACK2, IMG_MENU_BUTTON_TOUCH_BACK2, -1,
     &menu.setup.button.touch_back2, NULL,
     SCREEN_CTRL_ID_TOUCH_PREV_PAGE2,
     SCREEN_MASK_TOUCH2,
@@ -9367,7 +10351,7 @@ static struct
     TRUE, "previous page"
   },
   {
-    IMG_MENU_BUTTON_TOUCH_NEXT2, IMG_MENU_BUTTON_TOUCH_NEXT2,
+    IMG_MENU_BUTTON_TOUCH_NEXT2, IMG_MENU_BUTTON_TOUCH_NEXT2, -1,
     &menu.setup.button.touch_next2, NULL,
     SCREEN_CTRL_ID_TOUCH_NEXT_PAGE2,
     SCREEN_MASK_TOUCH2,
@@ -9447,10 +10431,17 @@ static void CreateScreenMenubuttons(void)
   for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
   {
     struct MenuPosInfo *pos = menubutton_info[i].pos;
+    int screen_mask = menubutton_info[i].screen_mask;
     boolean is_touch_button = menubutton_info[i].is_touch_button;
     boolean is_check_button = menubutton_info[i].check_value != NULL;
+    boolean is_score_button = (screen_mask & SCREEN_MASK_SCORES_INFO);
+    boolean has_gfx_pressed = (menubutton_info[i].gfx_pressed ==
+                               menubutton_info[i].gfx_unpressed);
+    boolean has_gfx_active = (menubutton_info[i].gfx_active != -1);
     Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
+    Bitmap *gd_bitmap_unpressed_alt, *gd_bitmap_pressed_alt;
     int gfx_unpressed, gfx_pressed;
+    int gfx_unpressed_alt, gfx_pressed_alt;
     int x, y, width, height;
     int gd_x1, gd_x2, gd_y1, gd_y2;
     int gd_x1a, gd_x2a, gd_y1a, gd_y2a;
@@ -9458,6 +10449,10 @@ static void CreateScreenMenubuttons(void)
     int type = GD_TYPE_NORMAL_BUTTON;
     boolean checked = FALSE;
 
+    // do not use touch buttons if overlay touch buttons are disabled
+    if (is_touch_button && !setup.touch.overlay_buttons)
+      continue;
+
     event_mask = menubutton_info[i].event_mask;
 
     x = (is_touch_button ? pos->x : mSX + GDI_ACTIVE_POS(pos->x));
@@ -9468,18 +10463,35 @@ static void CreateScreenMenubuttons(void)
 
     gfx_unpressed = menubutton_info[i].gfx_unpressed;
     gfx_pressed   = menubutton_info[i].gfx_pressed;
+    gfx_unpressed_alt = gfx_unpressed;
+    gfx_pressed_alt   = gfx_pressed;
+
+    if (has_gfx_active)
+    {
+      gfx_unpressed_alt = menubutton_info[i].gfx_active;
+
+      type = GD_TYPE_CHECK_BUTTON_2;
+
+      if (menubutton_info[i].check_value != NULL)
+       checked = *menubutton_info[i].check_value;
+    }
+
     gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
     gd_bitmap_pressed   = graphic_info[gfx_pressed].bitmap;
+    gd_bitmap_unpressed_alt = graphic_info[gfx_unpressed_alt].bitmap;
+    gd_bitmap_pressed_alt   = graphic_info[gfx_pressed_alt].bitmap;
+
     gd_x1 = graphic_info[gfx_unpressed].src_x;
     gd_y1 = graphic_info[gfx_unpressed].src_y;
     gd_x2 = graphic_info[gfx_pressed].src_x;
     gd_y2 = graphic_info[gfx_pressed].src_y;
-    gd_x1a = gd_x1;
-    gd_y1a = gd_y1;
-    gd_x2a = gd_x2;
-    gd_y2a = gd_y2;
 
-    if (is_touch_button)
+    gd_x1a = graphic_info[gfx_unpressed_alt].src_x;
+    gd_y1a = graphic_info[gfx_unpressed_alt].src_y;
+    gd_x2a = graphic_info[gfx_pressed_alt].src_x;
+    gd_y2a = graphic_info[gfx_pressed_alt].src_y;
+
+    if (has_gfx_pressed)
     {
       gd_x2 += graphic_info[gfx_pressed].pressed_xoffset;
       gd_y2 += graphic_info[gfx_pressed].pressed_yoffset;
@@ -9493,7 +10505,52 @@ static void CreateScreenMenubuttons(void)
       gd_y2a += graphic_info[gfx_pressed].active_yoffset;
 
       type = GD_TYPE_CHECK_BUTTON;
-      checked = *menubutton_info[i].check_value;
+
+      if (menubutton_info[i].check_value != NULL)
+       checked = *menubutton_info[i].check_value;
+    }
+
+    if (is_score_button)
+    {
+      // if x/y set to -1, dynamically place buttons next to title text
+      int title_width = getTextWidth(INFOTEXT_SCORE_ENTRY, FONT_TITLE_1);
+
+      // special compatibility handling for "Snake Bite" graphics set
+      if (strPrefix(leveldir_current->identifier, "snake_bite"))
+       title_width = strlen(INFOTEXT_SCORE_ENTRY) * 32;
+
+      // use "SX" here to center buttons (ignore horizontal draw offset)
+      if (pos->x == -1)
+       x = (id == SCREEN_CTRL_ID_PREV_LEVEL2 ?
+            SX + (SXSIZE - title_width) / 2 - width * 3 / 2 :
+            id == SCREEN_CTRL_ID_NEXT_LEVEL2 ?
+            SX + (SXSIZE + title_width) / 2 + width / 2 : 0);
+
+      // use "mSY" here to place buttons (respect vertical draw offset)
+      if (pos->y == -1)
+       y = (id == SCREEN_CTRL_ID_PREV_LEVEL2 ||
+            id == SCREEN_CTRL_ID_NEXT_LEVEL2 ? mSY + MENU_TITLE1_YPOS : 0);
+    }
+
+    if (id == SCREEN_CTRL_ID_LEVELSET_INFO)
+    {
+      if (pos->x == -1 && pos->y == -1)
+      {
+       // use "SX" here to place button (ignore draw offsets)
+       x = SX + SXSIZE - 2 * TILESIZE;
+       y = SY + SYSIZE - 2 * TILESIZE;
+
+       // special compatibility handling for "BD2K3" graphics set
+       if (strPrefix(leveldir_current->identifier, "BD2K3"))
+         x = SX + TILESIZE + MINI_TILESIZE;
+
+       // special compatibility handling for "jue0" graphics set
+       if (strPrefix(artwork.gfx_current_identifier, "jue0"))
+       {
+         x = SX + SXSIZE - 4 * TILESIZE;
+         y = SY + SYSIZE - 3 * TILESIZE;
+       }
+      }
     }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
@@ -9509,8 +10566,8 @@ static void CreateScreenMenubuttons(void)
                      GDI_CHECKED, checked,
                      GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
                      GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
-                      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1a, gd_y1a,
-                      GDI_ALT_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2a, gd_y2a,
+                      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap_unpressed_alt, gd_x1a, gd_y1a,
+                      GDI_ALT_DESIGN_PRESSED, gd_bitmap_pressed_alt, gd_x2a, gd_y2a,
                      GDI_DIRECT_DRAW, FALSE,
                      GDI_OVERLAY_TOUCH_BUTTON, is_touch_button,
                      GDI_EVENT_MASK, event_mask,
@@ -9737,6 +10794,15 @@ void FreeScreenGadgets(void)
     FreeGadget(screen_gadget[i]);
 }
 
+static void RedrawScreenMenuGadgets(int screen_mask)
+{
+  int i;
+
+  for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
+    if (screen_mask & menubutton_info[i].screen_mask)
+      RedrawGadget(screen_gadget[menubutton_info[i].gadget_id]);
+}
+
 static void MapScreenMenuGadgets(int screen_mask)
 {
   int i;
@@ -9787,11 +10853,54 @@ static void MapScreenGadgets(int num_entries)
     MapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
 }
 
+static void UnmapScreenGadgets(void)
+{
+  int i;
+
+  for (i = 0; i < NUM_SCREEN_SCROLLBUTTONS; i++)
+    UnmapGadget(screen_gadget[scrollbutton_info[i].gadget_id]);
+
+  for (i = 0; i < NUM_SCREEN_SCROLLBARS; i++)
+    UnmapGadget(screen_gadget[scrollbar_info[i].gadget_id]);
+}
+
 static void MapScreenTreeGadgets(TreeInfo *ti)
 {
   MapScreenGadgets(numTreeInfoInGroup(ti));
 }
 
+static void UnmapScreenTreeGadgets(void)
+{
+  UnmapScreenGadgets();
+}
+
+static void AdjustScoreInfoButtons_SelectScore(int x, int y1, int y2)
+{
+  struct GadgetInfo *gi_1 = screen_gadget[SCREEN_CTRL_ID_PREV_SCORE];
+  struct GadgetInfo *gi_2 = screen_gadget[SCREEN_CTRL_ID_NEXT_SCORE];
+  struct MenuPosInfo *pos_1 = menubutton_info[SCREEN_CTRL_ID_PREV_SCORE].pos;
+  struct MenuPosInfo *pos_2 = menubutton_info[SCREEN_CTRL_ID_NEXT_SCORE].pos;
+
+  if (pos_1->x == -1 && pos_1->y == -1)
+    ModifyGadget(gi_1, GDI_X, x, GDI_Y, y1, GDI_END);
+
+  if (pos_2->x == -1 && pos_2->y == -1)
+    ModifyGadget(gi_2, GDI_X, x, GDI_Y, y2, GDI_END);
+}
+
+static void AdjustScoreInfoButtons_PlayTape(int x, int y, boolean visible)
+{
+  struct GadgetInfo *gi = screen_gadget[SCREEN_CTRL_ID_PLAY_TAPE];
+  struct MenuPosInfo *pos = menubutton_info[SCREEN_CTRL_ID_PLAY_TAPE].pos;
+
+  // set gadget position dynamically, pre-defined or off-screen
+  int xx = (visible ? (pos->x == -1 ? x : pos->x) : POS_OFFSCREEN);
+  int yy = (visible ? (pos->y == -1 ? y : pos->y) : POS_OFFSCREEN);
+
+  ModifyGadget(gi, GDI_X, xx, GDI_Y, yy, GDI_END);
+  MapGadget(gi);       // (needed if deactivated on last score page)
+}
+
 static void HandleScreenGadgets(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
@@ -9810,6 +10919,26 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
       HandleMainMenu_SelectLevel(step, +1, NO_DIRECT_LEVEL_SELECT);
       break;
 
+    case SCREEN_CTRL_ID_PREV_LEVEL2:
+      HandleHallOfFame_SelectLevel(step, -1);
+      break;
+
+    case SCREEN_CTRL_ID_NEXT_LEVEL2:
+      HandleHallOfFame_SelectLevel(step, +1);
+      break;
+
+    case SCREEN_CTRL_ID_PREV_SCORE:
+      HandleScoreInfo_SelectScore(step, -1);
+      break;
+
+    case SCREEN_CTRL_ID_NEXT_SCORE:
+      HandleScoreInfo_SelectScore(step, +1);
+      break;
+
+    case SCREEN_CTRL_ID_PLAY_TAPE:
+      HandleScoreInfo_PlayTape();
+      break;
+
     case SCREEN_CTRL_ID_FIRST_LEVEL:
       HandleMainMenu_SelectLevel(MAX_LEVELS, -1, NO_DIRECT_LEVEL_SELECT);
       break;
@@ -9840,6 +10969,10 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
       PlaySolutionTape();
       break;
 
+    case SCREEN_CTRL_ID_LEVELSET_INFO:
+      DrawInfoScreen_FromMainMenu(INFO_MODE_LEVELSET);
+      break;
+
     case SCREEN_CTRL_ID_SWITCH_ECS_AGA:
       setup.prefer_aga_graphics = !setup.prefer_aga_graphics;
       DrawMainMenu();
@@ -9854,41 +10987,47 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
 
     case SCREEN_CTRL_ID_SCROLL_UP:
       if (game_status == GAME_MODE_NAMES)
-       HandleChoosePlayerName(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChoosePlayerName(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_LEVELS)
-       HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChooseLevelSet(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_LEVELNR)
-       HandleChooseLevelNr(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChooseLevelNr(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_SETUP)
-       HandleSetupScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleSetupScreen(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_INFO)
-       HandleInfoScreen(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleInfoScreen(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
+      else if (game_status == GAME_MODE_SCORES)
+       HandleHallOfFame(0, 0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
       break;
 
     case SCREEN_CTRL_ID_SCROLL_DOWN:
       if (game_status == GAME_MODE_NAMES)
-       HandleChoosePlayerName(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChoosePlayerName(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_LEVELS)
-       HandleChooseLevelSet(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChooseLevelSet(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_LEVELNR)
-       HandleChooseLevelNr(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleChooseLevelNr(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_SETUP)
-       HandleSetupScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleSetupScreen(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
       else if (game_status == GAME_MODE_INFO)
-       HandleInfoScreen(0,0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+       HandleInfoScreen(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
+      else if (game_status == GAME_MODE_SCORES)
+       HandleHallOfFame(0, 0, 0, +1 * SCROLL_LINE, MB_MENU_MARK);
       break;
 
     case SCREEN_CTRL_ID_SCROLL_VERTICAL:
       if (game_status == GAME_MODE_NAMES)
-       HandleChoosePlayerName(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
+       HandleChoosePlayerName(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
       else if (game_status == GAME_MODE_LEVELS)
-       HandleChooseLevelSet(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
+       HandleChooseLevelSet(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
       else if (game_status == GAME_MODE_LEVELNR)
-       HandleChooseLevelNr(0,0,999,gi->event.item_position,MB_MENU_INITIALIZE);
+       HandleChooseLevelNr(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
       else if (game_status == GAME_MODE_SETUP)
-       HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
+       HandleSetupScreen(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
       else if (game_status == GAME_MODE_INFO)
-       HandleInfoScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
+       HandleInfoScreen(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
+      else if (game_status == GAME_MODE_SCORES)
+       HandleHallOfFame(0, 0, 999, gi->event.item_position, MB_MENU_INITIALIZE);
       break;
 
     case SCREEN_CTRL_ID_NETWORK_SERVER:
@@ -9921,6 +11060,12 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
   }
 }
 
+void HandleScreenGadgetKeys(Key key)
+{
+  if (key == setup.shortcut.tape_play || key == KSYM_Return)
+    HandleScreenGadgets(screen_gadget[SCREEN_CTRL_ID_PLAY_TAPE]);
+}
+
 void DumpScreenIdentifiers(void)
 {
   int i;
@@ -10068,15 +11213,36 @@ static int UploadTapes(void)
 
 static boolean OfferUploadTapes(void)
 {
-  if (!Request("Upload all your tapes to the high score server now?", REQ_ASK))
+  if (!Request(setup.has_remaining_tapes ?
+              "Upload missing tapes to the high score server now?" :
+              "Upload all your tapes to the high score server now?", REQ_ASK))
     return FALSE;
 
+  // when uploading tapes, make sure that high score server is enabled
+  runtime.use_api_server = setup.use_api_server = TRUE;
+
   int num_tapes_uploaded = UploadTapes();
   char message[100];
 
   if (num_tapes_uploaded < 0)
   {
-    Request("Cannot upload tapes to score server!", REQ_CONFIRM);
+    num_tapes_uploaded = -num_tapes_uploaded - 1;
+
+    if (num_tapes_uploaded == 0)
+      sprintf(message, "Upload failed! No tapes uploaded!");
+    else if (num_tapes_uploaded == 1)
+      sprintf(message, "Upload failed! Only 1 tape uploaded!");
+    else
+      sprintf(message, "Upload failed! Only %d tapes uploaded!",
+             num_tapes_uploaded);
+
+    Request(message, REQ_CONFIRM);
+
+    // if uploading tapes failed, add tape upload entry to setup menu
+    setup.provide_uploading_tapes = TRUE;
+    setup.has_remaining_tapes = TRUE;
+
+    SaveSetup_ServerSetup();
 
     return FALSE;
   }
@@ -10090,29 +11256,38 @@ static boolean OfferUploadTapes(void)
 
   Request(message, REQ_CONFIRM);
 
+  if (num_tapes_uploaded > 0)
+    Request("New scores will be visible after a few minutes!", REQ_CONFIRM);
+
   // after all tapes have been uploaded, remove entry from setup menu
   setup.provide_uploading_tapes = FALSE;
+  setup.has_remaining_tapes = FALSE;
 
-  SaveSetup();
+  SaveSetup_ServerSetup();
 
   return TRUE;
 }
 
-void CheckUploadTapes(void)
+static void CheckUploadTapes(void)
 {
   if (!setup.ask_for_uploading_tapes)
     return;
 
-  // after asking for uploading all tapes once, do not ask again
+  // after asking for uploading tapes, do not ask again
   setup.ask_for_uploading_tapes = FALSE;
+  setup.ask_for_remaining_tapes = FALSE;
 
   if (directoryExists(getTapeDir(NULL)))
   {
     boolean tapes_uploaded = OfferUploadTapes();
 
     if (!tapes_uploaded)
-      Request("You can upload your tapes from the setup menu later!",
+    {
+      Request(setup.has_remaining_tapes ?
+             "You can upload missing tapes from the setup menu later!" :
+             "You can upload your tapes from the setup menu later!",
              REQ_CONFIRM);
+    }
   }
   else
   {
@@ -10120,5 +11295,27 @@ void CheckUploadTapes(void)
     setup.provide_uploading_tapes = FALSE;
   }
 
-  SaveSetup();
+  SaveSetup_ServerSetup();
+}
+
+static void UpgradePlayerUUID(void)
+{
+  ApiResetUUIDAsThread(getUUID());
+}
+
+static void CheckUpgradePlayerUUID(void)
+{
+  if (setup.player_version > 1)
+    return;
+
+  UpgradePlayerUUID();
+}
+
+void CheckApiServerTasks(void)
+{
+  // check if the player's UUID has to be upgraded
+  CheckUpgradePlayerUUID();
+
+  // check if there are any tapes to be uploaded
+  CheckUploadTapes();
 }
index 3d5a1316b1ed78c4580b6272571c2b8f034f274a..deba425c28ef73df7ab8fa1ed94e0fc19841d7e5 100644 (file)
@@ -24,6 +24,7 @@ void DrawAndFadeInMainMenu(int);
 void DrawMainMenu(void);
 void DrawHallOfFame(int);
 void DrawScreenAfterAddingSet(char *, int);
+void DrawInfoScreen_FromMainMenu(int);
 
 void RedrawSetupScreenAfterFullscreenToggle(void);
 void RedrawSetupScreenAfterScreenRotation(int);
@@ -34,10 +35,12 @@ void HandleChoosePlayerName(int, int, int, int, int);
 void HandleChooseLevelSet(int, int, int, int, int);
 void HandleChooseLevelNr(int, int, int, int, int);
 void HandleHallOfFame(int, int, int, int, int);
+void HandleScoreInfo(int, int, int, int, int);
 void HandleInfoScreen(int, int, int, int, int);
 void HandleSetupScreen(int, int, int, int, int);
 void HandleTypeName(Key);
 void HandleGameActions(void);
+void HandleScreenGadgetKeys(Key);
 
 void CreateScreenGadgets(void);
 void FreeScreenGadgets(void);
@@ -47,6 +50,6 @@ void setHideRelatedSetupEntries(void);
 void DumpScreenIdentifiers(void);
 boolean DoScreenAction(int);
 
-void CheckUploadTapes(void);
+void CheckApiServerTasks(void);
 
 #endif // SCREENS_H
index 793bf0cec0145eb04ddaea56a01f898092558626..ff0da179bf632f0185b8fd056201079c4a257180 100644 (file)
@@ -18,6 +18,8 @@
 #include "files.h"
 #include "network.h"
 #include "anim.h"
+#include "api.h"
+
 
 #define DEBUG_TAPE_WHEN_PLAYING                        FALSE
 
@@ -627,6 +629,30 @@ static void CloseTapeLogfile(void)
 // tape control functions
 // ============================================================================
 
+void TapeSetDateFromIsoDateString(char *date)
+{
+  int i;
+
+  // check ISO date string for correct length
+  if (strlen(date) != 10)
+    return;
+
+  // check ISO date string for correct format
+  for (i = 0; i < strlen(date); i++)
+    if (((i != 4 && i != 7) && (date[i] < '0' || date[i] > '9')) ||
+       ((i == 4 || i == 7) && (date[i] != '-')))
+      return;
+
+  int yy = (date[2] - '0') * 10 + (date[3] - '0');
+  int mm = (date[5] - '0') * 10 + (date[6] - '0');
+  int dd = (date[8] - '0') * 10 + (date[9] - '0');
+
+  if (mm < 1 || mm > 12 || dd < 1 || dd > 31)
+    return;
+
+  tape.date = 10000 * yy + 100 * (mm - 1) + dd;
+}
+
 void TapeSetDateFromEpochSeconds(time_t epoch_seconds)
 {
   struct tm *lt = localtime(&epoch_seconds);
@@ -662,6 +688,7 @@ void TapeErase(void)
   tape.level_nr = level_nr;
   tape.pos[tape.counter].delay = 0;
   tape.changed = TRUE;
+  tape.solved = FALSE;
 
   tape.random_seed = InitRND(level.random_seed);
 
@@ -671,6 +698,8 @@ void TapeErase(void)
 
   tape.property_bits = TAPE_PROPERTY_NONE;
 
+  tape.bd_replay = FALSE;
+
   TapeSetDateFromNow();
 
   for (i = 0; i < MAX_PLAYERS; i++)
@@ -758,6 +787,7 @@ static void TapeAppendRecording(void)
   // start recording
   tape.recording = TRUE;
   tape.changed = TRUE;
+  tape.solved = FALSE;
 
   // set current delay (for last played move)
   tape.pos[tape.counter].delay = tape.delay_played;
@@ -775,7 +805,9 @@ static void TapeAppendRecording(void)
 
 void TapeHaltRecording(void)
 {
-  tape.counter++;
+  // only advance tape counter if any input events have been recorded
+  if (tape.pos[tape.counter].delay > 0)
+    tape.counter++;
 
   // initialize delay for next tape entry (to be able to continue recording)
   if (tape.counter < MAX_TAPE_LEN)
@@ -830,6 +862,8 @@ boolean TapeAddAction(byte action[MAX_TAPE_ACTIONS])
     tape.pos[tape.counter].delay++;
   }
 
+  tape.changed = TRUE;
+
   return TRUE;
 }
 
@@ -841,6 +875,9 @@ void TapeRecordAction(byte action_raw[MAX_TAPE_ACTIONS])
   if (!tape.recording)         // (record action even when tape is paused)
     return;
 
+  if (!checkGameRunning())
+    return;
+
   for (i = 0; i < MAX_TAPE_ACTIONS; i++)
     action[i] = action_raw[i];
 
@@ -928,6 +965,10 @@ void TapeTogglePause(boolean toggle_mode)
 
     ModifyPauseButtons();
   }
+
+  // stop tape when leaving auto-pause after completely replaying tape
+  if (tape.playing && !tape.pausing && tape.counter >= tape.length)
+    TapeStop();
 }
 
 void TapeStartPlaying(void)
@@ -972,7 +1013,7 @@ void TapeStopPlaying(void)
   MapTapeEjectButton();
 }
 
-byte *TapePlayAction(void)
+byte *TapePlayActionExt(boolean bd_replay)
 {
   int update_delay = FRAMES_PER_SECOND / 2;
   boolean update_video_display = (FrameCounter % update_delay == 0);
@@ -983,23 +1024,35 @@ byte *TapePlayAction(void)
   if (!tape.playing || tape.pausing)
     return NULL;
 
+  if (!checkGameRunning())
+    return NULL;
+
+  if (tape.bd_replay && !bd_replay)
+    return NULL;
+
   if (tape.pause_before_end)  // stop some seconds before end of tape
   {
-    if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
+    if (TapeTime > (int)tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
     {
       TapeStopWarpForward();
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
 
+      if (setup.autorecord_after_replay)
+       TapeAppendRecording();
+
       return NULL;
     }
   }
 
   if (tape.counter >= tape.length)     // end of tape reached
   {
-    if (tape.warp_forward && !tape.auto_play)
+    if (!tape.auto_play)
     {
       TapeStopWarpForward();
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
+      if (setup.autorecord_after_replay)
+       TapeAppendRecording();
     }
     else
     {
@@ -1055,7 +1108,7 @@ byte *TapePlayAction(void)
   }
 
   tape.delay_played++;
-  if (tape.delay_played >= tape.pos[tape.counter].delay)
+  if (tape.delay_played >= tape.pos[tape.counter].delay || tape.bd_replay)
   {
     tape.counter++;
     tape.delay_played = 0;
@@ -1070,6 +1123,34 @@ byte *TapePlayAction(void)
   return action;
 }
 
+byte *TapePlayAction_BD(void)
+{
+  return TapePlayActionExt(TRUE);
+}
+
+byte *TapePlayAction(void)
+{
+  return TapePlayActionExt(FALSE);
+}
+
+byte *TapeCorrectAction_BD(byte *action)
+{
+  if (tape.playing)
+  {
+    // only read next tape action if not playing native BD replay
+    if (!TapeIsPlaying_ReplayBD())
+      action = TapePlayAction();
+  }
+  else if (tape.recording)
+  {
+    byte tape_action[MAX_TAPE_ACTIONS] = { action[0] };
+
+    TapeRecordAction(tape_action);
+  }
+
+  return action;
+}
+
 void TapeStop(void)
 {
   if (tape.pausing)
@@ -1088,6 +1169,27 @@ void TapeStop(void)
   }
 }
 
+static void TapeStopGameOrTape(boolean stop_game)
+{
+  if (score_info_tape_play || (!tape.playing && stop_game))
+    RequestQuitGame(FALSE);
+  else
+    TapeStop();
+}
+
+void TapeStopGame(void)
+{
+  if (game_status == GAME_MODE_MAIN)
+    return;
+
+  TapeStopGameOrTape(TRUE);
+}
+
+void TapeStopTape(void)
+{
+  TapeStopGameOrTape(FALSE);
+}
+
 unsigned int GetTapeLengthFrames(void)
 {
   unsigned int tape_length_frames = 0;
@@ -1154,22 +1256,25 @@ static void TapeSingleStep(void)
 
 void TapeQuickSave(void)
 {
-  if (game_status == GAME_MODE_MAIN)
+  if (game_status != GAME_MODE_PLAYING)
   {
-    Request("No game that can be saved!", REQ_CONFIRM);
+    Request("No game that could be saved!", REQ_CONFIRM);
 
     return;
   }
 
-  if (game_status != GAME_MODE_PLAYING)
+  if (!tape.recording)
+  {
+    Request("No recording that could be saved!", REQ_CONFIRM);
+
     return;
+  }
 
-  if (tape.recording)
-    TapeHaltRecording();       // prepare tape for saving on-the-fly
+  TapeHaltRecording();         // prepare tape for saving on-the-fly
 
   if (TAPE_IS_EMPTY(tape))
   {
-    Request("No tape that can be saved!", REQ_CONFIRM);
+    Request("No tape that could be saved!", REQ_CONFIRM);
 
     return;
   }
@@ -1244,11 +1349,85 @@ void TapeQuickLoad(void)
   }
 }
 
+static boolean checkRestartGame(char *message)
+{
+  if (game_status == GAME_MODE_MAIN)
+    return TRUE;
+
+  if (!hasStartedNetworkGame())
+    return FALSE;
+
+  if (level_editor_test_game)
+    return TRUE;
+
+  if (game.all_players_gone)
+    return TRUE;
+
+  if (!setup.ask_on_quit_game)
+    return TRUE;
+
+  if (Request(message, REQ_ASK | REQ_STAY_CLOSED))
+    return TRUE;
+
+  OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+
+  return FALSE;
+}
+
+void TapeRestartGame(void)
+{
+  if (score_info_tape_play)
+  {
+    TapeStartGamePlaying();
+
+    return;
+  }
+
+  if (!checkRestartGame("Restart game?"))
+    return;
+
+  // when using BD game engine, cover screen before fading out
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    game_bd.cover_screen = TRUE;
+
+  StartGameActions(network.enabled, setup.autorecord, level.random_seed);
+}
+
+void TapeReplayAndPauseBeforeEnd(void)
+{
+  if (score_info_tape_play)
+    return;
+
+  if (TAPE_IS_EMPTY(tape) && !tape.recording)
+  {
+    Request("No tape for this level!", REQ_CONFIRM);
+
+    return;
+  }
+
+  if (!checkRestartGame("Replay game and pause before end?"))
+    return;
+
+  TapeStop();
+  TapeStartGamePlaying();
+  TapeStartWarpForward(AUTOPLAY_MODE_WARP_NO_DISPLAY);
+
+  tape.pause_before_end = TRUE;
+  tape.quick_resume = TRUE;
+}
+
+boolean TapeIsPlaying_ReplayBD(void)
+{
+  return (tape.playing && tape.bd_replay);
+}
+
 boolean hasSolutionTape(void)
 {
   boolean tape_file_exists = fileExists(getSolutionTapeFilename(level_nr));
-  boolean level_has_tape = (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
-                           level.native_sp_level->demo.is_available);
+  boolean level_has_tape = ((level.game_engine_type == GAME_ENGINE_TYPE_BD &&
+                            level.native_bd_level->replay != NULL) ||
+                           (level.game_engine_type == GAME_ENGINE_TYPE_SP &&
+                            level.native_sp_level->demo.is_available));
 
   return (tape_file_exists || level_has_tape);
 }
@@ -1292,6 +1471,93 @@ boolean PlaySolutionTape(void)
   return TRUE;
 }
 
+static boolean PlayScoreTape_WaitForDownload(void)
+{
+  DelayCounter download_delay = { 10000 };
+
+  ResetDelayCounter(&download_delay);
+
+  // wait for score tape to be successfully downloaded (and fail on timeout)
+  while (!server_scores.tape_downloaded)
+  {
+    if (DelayReached(&download_delay))
+      return FALSE;
+
+    UPDATE_BUSY_STATE_NOT_LOADING();
+
+    Delay(20);
+  }
+
+  return TRUE;
+}
+
+boolean PlayScoreTape(int entry_nr)
+{
+  struct ScoreEntry *entry = &scores.entry[entry_nr];
+  char *tape_filename =
+    (entry->id == -1 ?
+     getScoreTapeFilename(entry->tape_basename, level_nr) :
+     getScoreCacheTapeFilename(entry->tape_basename, level_nr));
+  boolean download_tape = (!fileExists(tape_filename));
+
+  if (download_tape && entry->id == -1)
+  {
+    FadeSkipNextFadeIn();
+
+    Request("Cannot find score tape!", REQ_CONFIRM);
+
+    return FALSE;
+  }
+
+  server_scores.tape_downloaded = FALSE;
+
+  if (download_tape)
+    ApiGetScoreTapeAsThread(level_nr, entry->id, entry->tape_basename);
+
+  SetGameStatus(GAME_MODE_PLAYING);
+
+  FadeOut(REDRAW_FIELD);
+
+  if (download_tape && !PlayScoreTape_WaitForDownload())
+  {
+    SetGameStatus(GAME_MODE_SCOREINFO);
+    ClearField();
+
+    Request("Cannot download score tape from score server!", REQ_CONFIRM);
+
+    return FALSE;
+  }
+
+  if (!TAPE_IS_STOPPED(tape))
+    TapeStop();
+
+  // if tape recorder already contains a tape, remove it without asking
+  TapeErase();
+
+  if (entry->id == -1)
+    LoadScoreTape(entry->tape_basename, level_nr);
+  else
+    LoadScoreCacheTape(entry->tape_basename, level_nr);
+
+  if (TAPE_IS_EMPTY(tape))
+  {
+    SetGameStatus(GAME_MODE_SCOREINFO);
+    ClearField();
+
+    Request("Cannot load score tape for this level!", REQ_CONFIRM);
+
+    return FALSE;
+  }
+
+  FadeSkipNextFadeOut();
+
+  TapeStartGamePlaying();
+
+  score_info_tape_play = TRUE;
+
+  return TRUE;
+}
+
 static boolean checkTapesFromSameLevel(struct TapeInfo *t1, struct TapeInfo *t2)
 {
   return (strEqual(t1->level_identifier, t2->level_identifier) &&
@@ -1381,8 +1647,10 @@ static TreeInfo *getFirstValidAutoPlayEntry(TreeInfo *node)
 
 static void AutoPlayTapes_SetScoreEntry(int score, int time)
 {
+  char *name = (options.mytapes ? setup.player_name : options.player_name);
+
   // set unique basename for score tape (for uploading to score server)
-  strcpy(tape.score_tape_basename, getScoreTapeBasename(setup.player_name));
+  strcpy(tape.score_tape_basename, getScoreTapeBasename(name));
 
   // store score in first score entry
   scores.last_added = 0;
@@ -1402,15 +1670,14 @@ static void AutoPlayTapes_SetScoreEntry(int score, int time)
 
 static boolean AutoPlayTapes_WaitForUpload(void)
 {
-  unsigned int upload_delay = 0;
-  unsigned int upload_delay_value = 10000;
+  DelayCounter upload_delay = { 10000 };
 
   ResetDelayCounter(&upload_delay);
 
   // wait for score tape to be successfully uploaded (and fail on timeout)
   while (!server_scores.uploaded)
   {
-    if (DelayReached(&upload_delay, upload_delay_value))
+    if (DelayReached(&upload_delay))
     {
       PrintNoLog("\r");
       Print("- uploading score tape to score server - TIMEOUT.\n");
@@ -1612,6 +1879,7 @@ static int AutoPlayTapesExt(boolean initialize)
         global.autoplay_level[tape.level_nr] = TRUE;
 
       global.autoplay_all = FALSE;
+      options.mytapes = FALSE;
     }
 
     if (autoplay.all_levelsets)
@@ -1667,6 +1935,41 @@ static int AutoPlayTapesExt(boolean initialize)
       init_level_set = FALSE;
     }
 
+    if (autoplay.all_levelsets && global.autoplay_mode == AUTOPLAY_MODE_UPLOAD)
+    {
+      boolean skip_levelset = FALSE;
+
+      if (!directoryExists(getTapeDir(autoplay.leveldir->subdir)))
+      {
+       Print("No tape directory for this level set found -- skipping.\n");
+
+       skip_levelset = TRUE;
+      }
+
+      if (CheckTapeDirectoryUploadsComplete(autoplay.leveldir->subdir))
+      {
+       Print("All tapes for this level set already uploaded -- skipping.\n");
+
+       skip_levelset = TRUE;
+      }
+
+      if (skip_levelset)
+      {
+       PrintTapeReplaySummary(&autoplay);
+
+       // continue with next level set
+       autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir);
+
+       // all level sets processed
+       if (autoplay.leveldir == NULL)
+         break;
+
+       init_level_set = TRUE;
+
+       continue;
+      }
+    }
+
     if (global.autoplay_mode != AUTOPLAY_MODE_FIX || patch_nr == 0)
       level_nr = autoplay.level_nr++;
 
@@ -1680,6 +1983,9 @@ static int AutoPlayTapesExt(boolean initialize)
       if (!autoplay.all_levelsets)
        break;
 
+      if (global.autoplay_mode == AUTOPLAY_MODE_UPLOAD)
+       MarkTapeDirectoryUploadsAsComplete(autoplay.leveldir->subdir);
+
       // continue with next level set
       autoplay.leveldir = getNextValidAutoPlayEntry(autoplay.leveldir);
 
@@ -1701,12 +2007,8 @@ static int AutoPlayTapesExt(boolean initialize)
     if (!global.autoplay_all && !global.autoplay_level[level_nr])
       continue;
 
-    char *tape_filename = (autoplay.tape_filename ? autoplay.tape_filename :
-                           options.mytapes ? getTapeFilename(level_nr) :
-                           getSolutionTapeFilename(level_nr));
-
-    // speed things up in case of missing tapes (by skipping loading level)
-    if (!fileExists(tape_filename))
+    // speed things up in case of missing private tapes (skip loading level)
+    if (options.mytapes && !fileExists(getTapeFilename(level_nr)))
     {
       autoplay.num_tape_missing++;
 
@@ -1744,7 +2046,7 @@ static int AutoPlayTapesExt(boolean initialize)
     {
       autoplay.num_tape_missing++;
 
-      Print("Tape %03d: (invalid tape)\n", level_nr);
+      Print("Tape %03d: (no tape found)\n", level_nr);
 
       continue;
     }
@@ -1844,7 +2146,7 @@ static int AutoPlayTapesExt(boolean initialize)
 
       if (!success)
       {
-       num_tapes = -1;
+       num_tapes = -num_tapes;
 
        break;
       }
@@ -2303,7 +2605,7 @@ static void HandleTapeButtonsExt(int id)
       break;
 
     case TAPE_CTRL_ID_STOP:
-      TapeStop();
+      TapeStopTape();
 
       break;
 
index 4b914c73d2ac394debdce2a290264708861062ec..361806ad0ed92b6f591f623fc9f4abfdda8d80f5 100644 (file)
 
 
 // values for TapeTogglePause()
-#define        TAPE_TOGGLE_AUTOMATIC   0
-#define        TAPE_TOGGLE_MANUAL      (1 << 0)
-#define        TAPE_TOGGLE_PLAY_PAUSE  (1 << 1)
+#define TAPE_TOGGLE_AUTOMATIC          0
+#define TAPE_TOGGLE_MANUAL             (1 << 0)
+#define TAPE_TOGGLE_PLAY_PAUSE         (1 << 1)
 
 // values for tape properties
-#define MAX_TAPE_LEN           (10000 * FRAMES_PER_SECOND) // max.time x fps
+#define MAX_TAPE_LEN                   (10000 * FRAMES_PER_SECOND)     // max.time x fps
 
 // values for tape action array positions
-#define TAPE_ACTION_LX         (MAX_PLAYERS + 0)
-#define TAPE_ACTION_LY         (MAX_PLAYERS + 1)
-#define TAPE_ACTION_BUTTON     (MAX_PLAYERS + 2)
+#define TAPE_ACTION_LX                 (MAX_PLAYERS + 0)
+#define TAPE_ACTION_LY                 (MAX_PLAYERS + 1)
+#define TAPE_ACTION_BUTTON             (MAX_PLAYERS + 2)
 
-#define MAX_TAPE_ACTIONS       (MAX_PLAYERS + 3)
+#define MAX_TAPE_ACTIONS               (MAX_PLAYERS + 3)
 
 // values for tape actions stored in tape file
 #define TAPE_USE_KEY_ACTIONS_ONLY      0
 #define MAX_SCORE_TAPE_BASENAME_LEN    24
 
 // some positions in the video tape control window
-#define VIDEO_DISPLAY1_XPOS    5
-#define VIDEO_DISPLAY1_YPOS    5
-#define VIDEO_DISPLAY2_XPOS    5
-#define VIDEO_DISPLAY2_YPOS    41
-#define VIDEO_DISPLAY_XSIZE    90
-#define VIDEO_DISPLAY_YSIZE    31
-#define VIDEO_BUTTON_XSIZE     18
-#define VIDEO_BUTTON_YSIZE     18
-#define VIDEO_CONTROL_XPOS     5
-#define VIDEO_CONTROL_YPOS     77
-#define VIDEO_CONTROL_XSIZE    VIDEO_DISPLAY_XSIZE
-#define VIDEO_CONTROL_YSIZE    VIDEO_BUTTON_YSIZE
+#define VIDEO_DISPLAY1_XPOS            5
+#define VIDEO_DISPLAY1_YPOS            5
+#define VIDEO_DISPLAY2_XPOS            5
+#define VIDEO_DISPLAY2_YPOS            41
+#define VIDEO_DISPLAY_XSIZE            90
+#define VIDEO_DISPLAY_YSIZE            31
+#define VIDEO_BUTTON_XSIZE             18
+#define VIDEO_BUTTON_YSIZE             18
+#define VIDEO_CONTROL_XPOS             5
+#define VIDEO_CONTROL_YPOS             77
+#define VIDEO_CONTROL_XSIZE            VIDEO_DISPLAY_XSIZE
+#define VIDEO_CONTROL_YSIZE            VIDEO_BUTTON_YSIZE
 
 // values for video tape control
-#define VIDEO_STATE_PLAY_OFF   (1 << 0)
-#define VIDEO_STATE_PLAY_ON    (1 << 1)
-#define VIDEO_STATE_REC_OFF    (1 << 2)
-#define VIDEO_STATE_REC_ON     (1 << 3)
-#define VIDEO_STATE_PAUSE_OFF  (1 << 4)
-#define VIDEO_STATE_PAUSE_ON   (1 << 5)
-#define VIDEO_STATE_DATE_OFF   (1 << 6)
-#define VIDEO_STATE_DATE_ON    (1 << 7)
-#define VIDEO_STATE_TIME_OFF   (1 << 8)
-#define VIDEO_STATE_TIME_ON    (1 << 9)
-#define VIDEO_STATE_FRAME_OFF  (1 << 10)
-#define VIDEO_STATE_FRAME_ON   (1 << 11)
-#define VIDEO_STATE_FFWD_OFF   (1 << 12)
-#define VIDEO_STATE_FFWD_ON    (1 << 13)
-#define VIDEO_STATE_WARP_OFF   (1 << 14)
-#define VIDEO_STATE_WARP_ON    (1 << 15)
-#define VIDEO_STATE_WARP2_OFF  (1 << 16)
-#define VIDEO_STATE_WARP2_ON   (1 << 17)
-#define VIDEO_STATE_PBEND_OFF  (1 << 18)
-#define VIDEO_STATE_PBEND_ON   (1 << 19)
-#define VIDEO_STATE_1STEP_OFF  (1 << 20)
-#define VIDEO_STATE_1STEP_ON   (1 << 21)
-
-#define VIDEO_PRESS_PLAY_ON    (1 << 22)
-#define VIDEO_PRESS_PLAY_OFF   (1 << 23)
-#define VIDEO_PRESS_REC_ON     (1 << 24)
-#define VIDEO_PRESS_REC_OFF    (1 << 25)
-#define VIDEO_PRESS_PAUSE_ON   (1 << 26)
-#define VIDEO_PRESS_PAUSE_OFF  (1 << 27)
-#define VIDEO_PRESS_STOP_ON    (1 << 28)
-#define VIDEO_PRESS_STOP_OFF   (1 << 29)
-#define VIDEO_PRESS_EJECT_ON   (1 << 30)
-#define VIDEO_PRESS_EJECT_OFF  (1 << 31)
-
-#define VIDEO_STATE_PLAY(x)  ((x) ? VIDEO_STATE_PLAY_ON : VIDEO_STATE_PLAY_OFF)
-#define VIDEO_STATE_REC(x)   ((x) ? VIDEO_STATE_REC_ON  : VIDEO_STATE_REC_OFF)
-#define VIDEO_STATE_PAUSE(x) ((x) ? VIDEO_STATE_PAUSE_ON: VIDEO_STATE_PAUSE_OFF)
-#define VIDEO_STATE_DATE(x)  ((x) ? VIDEO_STATE_DATE_ON : VIDEO_STATE_DATE_OFF)
-#define VIDEO_STATE_TIME(x)  ((x) ? VIDEO_STATE_TIME_ON : VIDEO_STATE_TIME_OFF)
-#define VIDEO_STATE_FRAME(x) ((x) ? VIDEO_STATE_FRAME_ON: VIDEO_STATE_FRAME_OFF)
-#define VIDEO_STATE_FFWD(x)  ((x) ? VIDEO_STATE_FFWD_ON : VIDEO_STATE_FFWD_OFF)
-#define VIDEO_STATE_WARP(x)  ((x) ? VIDEO_STATE_WARP_ON : VIDEO_STATE_WARP_OFF)
-#define VIDEO_STATE_WARP2(x) ((x) ? VIDEO_STATE_WARP2_ON: VIDEO_STATE_WARP2_OFF)
-#define VIDEO_STATE_PBEND(x) ((x) ? VIDEO_STATE_PBEND_ON: VIDEO_STATE_PBEND_OFF)
-#define VIDEO_STATE_1STEP(x) ((x) ? VIDEO_STATE_1STEP_ON: VIDEO_STATE_1STEP_OFF)
-
-#define VIDEO_PRESS_PLAY(x)  ((x) ? VIDEO_PRESS_PLAY_ON : VIDEO_PRESS_PLAY_OFF)
-#define VIDEO_PRESS_REC(x)   ((x) ? VIDEO_PRESS_REC_ON  : VIDEO_PRESS_REC_OFF)
-#define VIDEO_PRESS_PAUSE(x) ((x) ? VIDEO_PRESS_PAUSE_ON: VIDEO_PRESS_PAUSE_OFF)
-#define VIDEO_PRESS_STOP(x)  ((x) ? VIDEO_PRESS_STOP_ON : VIDEO_PRESS_STOP_OFF)
-#define VIDEO_PRESS_EJECT(x) ((x) ? VIDEO_PRESS_EJECT_ON: VIDEO_PRESS_EJECT_OFF)
+#define VIDEO_STATE_PLAY_OFF           (1u << 0)
+#define VIDEO_STATE_PLAY_ON            (1u << 1)
+#define VIDEO_STATE_REC_OFF            (1u << 2)
+#define VIDEO_STATE_REC_ON             (1u << 3)
+#define VIDEO_STATE_PAUSE_OFF          (1u << 4)
+#define VIDEO_STATE_PAUSE_ON           (1u << 5)
+#define VIDEO_STATE_DATE_OFF           (1u << 6)
+#define VIDEO_STATE_DATE_ON            (1u << 7)
+#define VIDEO_STATE_TIME_OFF           (1u << 8)
+#define VIDEO_STATE_TIME_ON            (1u << 9)
+#define VIDEO_STATE_FRAME_OFF          (1u << 10)
+#define VIDEO_STATE_FRAME_ON           (1u << 11)
+#define VIDEO_STATE_FFWD_OFF           (1u << 12)
+#define VIDEO_STATE_FFWD_ON            (1u << 13)
+#define VIDEO_STATE_WARP_OFF           (1u << 14)
+#define VIDEO_STATE_WARP_ON            (1u << 15)
+#define VIDEO_STATE_WARP2_OFF          (1u << 16)
+#define VIDEO_STATE_WARP2_ON           (1u << 17)
+#define VIDEO_STATE_PBEND_OFF          (1u << 18)
+#define VIDEO_STATE_PBEND_ON           (1u << 19)
+#define VIDEO_STATE_1STEP_OFF          (1u << 20)
+#define VIDEO_STATE_1STEP_ON           (1u << 21)
+
+#define VIDEO_PRESS_PLAY_ON            (1u << 22)
+#define VIDEO_PRESS_PLAY_OFF           (1u << 23)
+#define VIDEO_PRESS_REC_ON             (1u << 24)
+#define VIDEO_PRESS_REC_OFF            (1u << 25)
+#define VIDEO_PRESS_PAUSE_ON           (1u << 26)
+#define VIDEO_PRESS_PAUSE_OFF          (1u << 27)
+#define VIDEO_PRESS_STOP_ON            (1u << 28)
+#define VIDEO_PRESS_STOP_OFF           (1u << 29)
+#define VIDEO_PRESS_EJECT_ON           (1u << 30)
+#define VIDEO_PRESS_EJECT_OFF          (1u << 31)
+
+#define VIDEO_STATE_PLAY(x)            ((x) ? VIDEO_STATE_PLAY_ON : VIDEO_STATE_PLAY_OFF)
+#define VIDEO_STATE_REC(x)             ((x) ? VIDEO_STATE_REC_ON  : VIDEO_STATE_REC_OFF)
+#define VIDEO_STATE_PAUSE(x)           ((x) ? VIDEO_STATE_PAUSE_ON: VIDEO_STATE_PAUSE_OFF)
+#define VIDEO_STATE_DATE(x)            ((x) ? VIDEO_STATE_DATE_ON : VIDEO_STATE_DATE_OFF)
+#define VIDEO_STATE_TIME(x)            ((x) ? VIDEO_STATE_TIME_ON : VIDEO_STATE_TIME_OFF)
+#define VIDEO_STATE_FRAME(x)           ((x) ? VIDEO_STATE_FRAME_ON: VIDEO_STATE_FRAME_OFF)
+#define VIDEO_STATE_FFWD(x)            ((x) ? VIDEO_STATE_FFWD_ON : VIDEO_STATE_FFWD_OFF)
+#define VIDEO_STATE_WARP(x)            ((x) ? VIDEO_STATE_WARP_ON : VIDEO_STATE_WARP_OFF)
+#define VIDEO_STATE_WARP2(x)           ((x) ? VIDEO_STATE_WARP2_ON: VIDEO_STATE_WARP2_OFF)
+#define VIDEO_STATE_PBEND(x)           ((x) ? VIDEO_STATE_PBEND_ON: VIDEO_STATE_PBEND_OFF)
+#define VIDEO_STATE_1STEP(x)           ((x) ? VIDEO_STATE_1STEP_ON: VIDEO_STATE_1STEP_OFF)
+
+#define VIDEO_PRESS_PLAY(x)            ((x) ? VIDEO_PRESS_PLAY_ON : VIDEO_PRESS_PLAY_OFF)
+#define VIDEO_PRESS_REC(x)             ((x) ? VIDEO_PRESS_REC_ON  : VIDEO_PRESS_REC_OFF)
+#define VIDEO_PRESS_PAUSE(x)           ((x) ? VIDEO_PRESS_PAUSE_ON: VIDEO_PRESS_PAUSE_OFF)
+#define VIDEO_PRESS_STOP(x)            ((x) ? VIDEO_PRESS_STOP_ON : VIDEO_PRESS_STOP_OFF)
+#define VIDEO_PRESS_EJECT(x)           ((x) ? VIDEO_PRESS_EJECT_ON: VIDEO_PRESS_EJECT_OFF)
 
 // tags to draw video display labels or symbols only
 // (negative values to prevent misinterpretation in DrawVideoDisplay(), where
@@ -184,9 +184,9 @@ struct TapeTextInfo
 
 struct TapeInfo
 {
-  int file_version;    // file format version the tape is stored with
-  int game_version;    // game release version the tape was created with
-  int engine_version;  // game engine version the tape was recorded with
+  int file_version;            // file format version the tape is stored with
+  int game_version;            // game release version the tape was created with
+  int engine_version;          // game engine version the tape was recorded with
 
   char score_tape_basename[MAX_FILENAME_LEN + 1];
   char level_identifier[MAX_FILENAME_LEN + 1];
@@ -210,6 +210,7 @@ struct TapeInfo
   boolean quick_resume;
   boolean single_step;
   boolean changed;
+  boolean solved;
   boolean player_participates[MAX_PLAYERS];
   int num_participating_players;
   int centered_player_nr_next;
@@ -222,6 +223,9 @@ struct TapeInfo
   // bits to indicate which tape properties are stored in this tape
   byte property_bits;
 
+  // special game_engine_flags;
+  boolean bd_replay;
+
   // visible playfield size when recording this tape (for team mode)
   int scr_fieldx;
   int scr_fieldy;
@@ -250,28 +254,38 @@ void DrawCompleteVideoDisplay(void);
 void TapeDeactivateDisplayOn(void);
 void TapeDeactivateDisplayOff(boolean);
 
+void TapeSetDateFromIsoDateString(char *);
 void TapeSetDateFromEpochSeconds(time_t);
 void TapeSetDateFromNow(void);
 
 void TapeStartRecording(int);
 void TapeHaltRecording(void);
 void TapeStopRecording(void);
-boolean TapeAddAction(byte *);
-void TapeRecordAction(byte *);
+boolean TapeAddAction(byte[MAX_TAPE_ACTIONS]);
+void TapeRecordAction(byte[MAX_TAPE_ACTIONS]);
 void TapeTogglePause(boolean);
 void TapeStartPlaying(void);
 void TapeStopPlaying(void);
+byte *TapePlayActionExt(boolean);
+byte *TapePlayAction_BD(void);
 byte *TapePlayAction(void);
+byte *TapeCorrectAction_BD(byte *);
 void TapeStop(void);
+void TapeStopGame(void);
+void TapeStopTape(void);
 void TapeErase(void);
 unsigned int GetTapeLengthFrames(void);
 unsigned int GetTapeLengthSeconds(void);
 void TapeQuickSave(void);
 void TapeQuickLoad(void);
+void TapeRestartGame(void);
+void TapeReplayAndPauseBeforeEnd(void);
+boolean TapeIsPlaying_ReplayBD(void);
 
 boolean hasSolutionTape(void);
 boolean InsertSolutionTape(void);
 boolean PlaySolutionTape(void);
+boolean PlayScoreTape(int);
 
 void UndoTape(void);
 void FixTape_ForceSinglePlayer(void);
index c859e633975d4e6819e78a298c16ba0db0d3e134..1881220a079c35dc07baa93eb65611af9040a447 100644 (file)
@@ -165,8 +165,17 @@ static struct DoorPartControlInfo door_part_controls[] =
   }
 };
 
+static struct XY xy_topdown[] =
+{
+  {  0, -1 },
+  { -1,  0 },
+  { +1,  0 },
+  {  0, +1 }
+};
+
 
 // forward declaration for internal use
+static void MapToolButtons(unsigned int);
 static void UnmapToolButtons(void);
 static void HandleToolButtons(struct GadgetInfo *);
 static int el_act_dir2crm(int, int, int);
@@ -491,7 +500,9 @@ void RedrawPlayfield(void)
   if (game_status != GAME_MODE_PLAYING)
     return;
 
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    RedrawPlayfield_BD(TRUE);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     RedrawPlayfield_EM(TRUE);
   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
     RedrawPlayfield_SP(TRUE);
@@ -512,6 +523,10 @@ static void DrawMaskedBorderExt_Rect(int x, int y, int width, int height,
   Bitmap *src_bitmap = getGlobalBorderBitmapFromStatus(global.border_status);
   Bitmap *dst_bitmap = gfx.masked_border_bitmap_ptr;
 
+  // may happen for "border.draw_masked.*" with undefined "global.border.*"
+  if (src_bitmap == NULL)
+    return;
+
   if (x == -1 && y == -1)
     return;
 
@@ -622,6 +637,10 @@ void DrawMaskedBorderToTarget(int draw_target)
       gfx.masked_border_bitmap_ptr = gfx.fade_bitmap_target;
     }
 
+    // always use global border for PLAYING when restarting the game
+    if (global.border_status == GAME_MODE_PSEUDO_RESTARTING)
+      global.border_status = GAME_MODE_PLAYING;
+
     DrawMaskedBorderExt(REDRAW_ALL, draw_target);
 
     global.border_status = last_border_status;
@@ -629,9 +648,11 @@ void DrawMaskedBorderToTarget(int draw_target)
   }
 }
 
-void DrawTileCursor(int draw_target)
+void DrawTileCursor(int draw_target, int drawing_stage)
 {
-  DrawTileCursor_MM(draw_target, game_status == GAME_MODE_PLAYING);
+  int tile_cursor_active = (game_status == GAME_MODE_PLAYING);
+
+  DrawTileCursor_MM(draw_target, drawing_stage, tile_cursor_active);
 }
 
 void BlitScreenToBitmapExt_RND(Bitmap *target_bitmap, int fx, int fy)
@@ -649,7 +670,9 @@ void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
 
 void BlitScreenToBitmap(Bitmap *target_bitmap)
 {
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    BlitScreenToBitmap_BD(target_bitmap);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     BlitScreenToBitmap_EM(target_bitmap);
   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
     BlitScreenToBitmap_SP(target_bitmap);
@@ -763,7 +786,7 @@ void BackToFront(void)
     DrawFramesPerSecond();
 
   // remove playfield redraw before potentially merging with doors redraw
-  if (DrawingDeactivated(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE))
+  if (DrawingDeactivated(REAL_SX, REAL_SY))
     redraw_mask &= ~REDRAW_FIELD;
 
   // redraw complete window if both playfield and (some) doors need redraw
@@ -964,6 +987,10 @@ static void SetScreenStates_BeforeFadingOut(void)
 static void SetScreenStates_AfterFadingOut(void)
 {
   global.border_status = game_status;
+
+  // always use global border for PLAYING when restarting the game
+  if (global.border_status == GAME_MODE_PSEUDO_RESTARTING)
+    global.border_status = GAME_MODE_PLAYING;
 }
 
 void FadeIn(int fade_mask)
@@ -1003,6 +1030,10 @@ void FadeOut(int fade_mask)
       fade_type_skip != FADE_MODE_SKIP_FADE_OUT)
     BackToFront();
 
+  // when using BD game engine, cover playfield before fading out after a game
+  if (game_bd.cover_screen)
+    CoverScreen_BD();
+
   SetScreenStates_BeforeFadingOut();
 
   SetTileCursorActive(FALSE);
@@ -1091,82 +1122,108 @@ void FadeSkipNextFadeOut(void)
   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
 }
 
-static Bitmap *getBitmapFromGraphicOrDefault(int graphic, int default_graphic)
+static int getGlobalGameStatus(int status)
+{
+  return (status == GAME_MODE_PSEUDO_TYPENAME ? GAME_MODE_MAIN :
+         status == GAME_MODE_SCOREINFO       ? GAME_MODE_SCORES :
+         status);
+}
+
+int getImageFromGraphicOrDefault(int graphic, int default_graphic)
 {
   if (graphic == IMG_UNDEFINED)
-    return NULL;
+    return IMG_UNDEFINED;
 
   boolean redefined = getImageListEntryFromImageID(graphic)->redefined;
 
   return (graphic_info[graphic].bitmap != NULL || redefined ?
-         graphic_info[graphic].bitmap :
-         graphic_info[default_graphic].bitmap);
+         graphic : default_graphic);
 }
 
-static Bitmap *getBackgroundBitmap(int graphic)
+static int getBackgroundImage(int graphic)
 {
-  return getBitmapFromGraphicOrDefault(graphic, IMG_BACKGROUND);
+  return getImageFromGraphicOrDefault(graphic, IMG_BACKGROUND);
 }
 
-static Bitmap *getGlobalBorderBitmap(int graphic)
+static int getGlobalBorderImage(int graphic)
 {
-  return getBitmapFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
+  return getImageFromGraphicOrDefault(graphic, IMG_GLOBAL_BORDER);
 }
 
-Bitmap *getGlobalBorderBitmapFromStatus(int status)
+Bitmap *getGlobalBorderBitmapFromStatus(int status_raw)
 {
+  int status = getGlobalGameStatus(status_raw);
   int graphic =
-    (status == GAME_MODE_MAIN ||
-     status == GAME_MODE_PSEUDO_TYPENAME       ? IMG_GLOBAL_BORDER_MAIN :
-     status == GAME_MODE_SCORES                        ? IMG_GLOBAL_BORDER_SCORES :
-     status == GAME_MODE_EDITOR                        ? IMG_GLOBAL_BORDER_EDITOR :
-     status == GAME_MODE_PLAYING               ? IMG_GLOBAL_BORDER_PLAYING :
+    (status == GAME_MODE_MAIN    ? IMG_GLOBAL_BORDER_MAIN :
+     status == GAME_MODE_SCORES  ? IMG_GLOBAL_BORDER_SCORES :
+     status == GAME_MODE_EDITOR  ? IMG_GLOBAL_BORDER_EDITOR :
+     status == GAME_MODE_PLAYING ? IMG_GLOBAL_BORDER_PLAYING :
      IMG_GLOBAL_BORDER);
+  int graphic_final = getGlobalBorderImage(graphic);
+
+  return graphic_info[graphic_final].bitmap;
+}
 
-  return getGlobalBorderBitmap(graphic);
+void SetBackgroundImage(int graphic, int redraw_mask)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+  struct GraphicInfo g_undefined = { 0 };
+
+  if (graphic == IMG_UNDEFINED)
+    g = &g_undefined;
+
+  // always use original size bitmap for backgrounds, if existing
+  Bitmap *bitmap = (g->bitmaps != NULL &&
+                   g->bitmaps[IMG_BITMAP_PTR_ORIGINAL] != NULL ?
+                   g->bitmaps[IMG_BITMAP_PTR_ORIGINAL] : g->bitmap);
+
+  // remove every mask before setting mask for window, and
+  // remove window area mask before setting mask for main or door area
+  int remove_mask = (redraw_mask == REDRAW_ALL ? 0xffff : REDRAW_ALL);
+
+  // (!!! TO BE FIXED: The whole REDRAW_* system really sucks! !!!)
+  SetBackgroundBitmap(NULL, remove_mask, 0, 0, 0, 0);  // !!! FIX THIS !!!
+  SetBackgroundBitmap(bitmap, redraw_mask,
+                     g->src_x, g->src_y,
+                     g->width, g->height);
 }
 
 void SetWindowBackgroundImageIfDefined(int graphic)
 {
   if (graphic_info[graphic].bitmap)
-    SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
+    SetBackgroundImage(graphic, REDRAW_ALL);
 }
 
 void SetMainBackgroundImageIfDefined(int graphic)
 {
   if (graphic_info[graphic].bitmap)
-    SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
+    SetBackgroundImage(graphic, REDRAW_FIELD);
 }
 
 void SetDoorBackgroundImageIfDefined(int graphic)
 {
   if (graphic_info[graphic].bitmap)
-    SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
+    SetBackgroundImage(graphic, REDRAW_DOOR_1);
 }
 
 void SetWindowBackgroundImage(int graphic)
 {
-  SetWindowBackgroundBitmap(getBackgroundBitmap(graphic));
+  SetBackgroundImage(getBackgroundImage(graphic), REDRAW_ALL);
 }
 
 void SetMainBackgroundImage(int graphic)
 {
-  SetMainBackgroundBitmap(getBackgroundBitmap(graphic));
+  SetBackgroundImage(getBackgroundImage(graphic), REDRAW_FIELD);
 }
 
 void SetDoorBackgroundImage(int graphic)
 {
-  SetDoorBackgroundBitmap(getBackgroundBitmap(graphic));
+  SetBackgroundImage(getBackgroundImage(graphic), REDRAW_DOOR_1);
 }
 
 void SetPanelBackground(void)
 {
-  struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
-
-  BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
-                 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
-
-  SetDoorBackgroundBitmap(bitmap_db_panel);
+  SetDoorBackgroundImage(IMG_BACKGROUND_PANEL);
 }
 
 void DrawBackground(int x, int y, int width, int height)
@@ -1422,7 +1479,7 @@ void FloodFillLevelExt(int start_x, int start_y, int fill_element,
                       int max_fieldx, int max_fieldy)
 {
   static struct XY stack_buffer[MAX_LEV_FIELDX * MAX_LEV_FIELDY];
-  static struct XY check[4] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
+  struct XY *check = xy_topdown;
   int old_element = field[start_x][start_y];
   int stack_pos = 0;
 
@@ -1468,11 +1525,18 @@ void SetRandomAnimationValue(int x, int y)
   gfx.anim_random_frame = GfxRandom[x][y];
 }
 
+void SetAnimationFirstLevel(int first_level)
+{
+  gfx.anim_first_level = first_level;
+}
+
 int getGraphicAnimationFrame(int graphic, int sync_frame)
 {
   // animation synchronized with global frame counter, not move position
   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
     sync_frame = FrameCounter;
+  else if (graphic_info[graphic].anim_global_anim_sync)
+    sync_frame = getGlobalAnimSyncFrame();
 
   return getAnimationFrame(graphic_info[graphic].anim_frames,
                           graphic_info[graphic].anim_delay,
@@ -1481,6 +1545,40 @@ int getGraphicAnimationFrame(int graphic, int sync_frame)
                           sync_frame);
 }
 
+int getGraphicAnimationFrameXY(int graphic, int lx, int ly)
+{
+  if (graphic_info[graphic].anim_mode & ANIM_TILED)
+  {
+    struct GraphicInfo *g = &graphic_info[graphic];
+    int xsize = MAX(1, g->anim_frames_per_line);
+    int ysize = MAX(1, g->anim_frames / xsize);
+    int xoffset = g->anim_start_frame % xsize;
+    int yoffset = g->anim_start_frame % ysize;
+    // may be needed if screen field is significantly larger than playfield
+    int x = (lx + xoffset + SCR_FIELDX * xsize) % xsize;
+    int y = (ly + yoffset + SCR_FIELDY * ysize) % ysize;
+    int sync_frame = y * xsize + x;
+
+    return sync_frame % g->anim_frames;
+  }
+  else if (graphic_info[graphic].anim_mode & ANIM_RANDOM_STATIC)
+  {
+    struct GraphicInfo *g = &graphic_info[graphic];
+    // may be needed if screen field is significantly larger than playfield
+    int x = (lx + SCR_FIELDX * lev_fieldx) % lev_fieldx;
+    int y = (ly + SCR_FIELDY * lev_fieldy) % lev_fieldy;
+    int sync_frame = GfxRandomStatic[x][y];
+
+    return sync_frame % g->anim_frames;
+  }
+  else
+  {
+    int sync_frame = (IN_LEV_FIELD(lx, ly) ? GfxFrame[lx][ly] : -1);
+
+    return getGraphicAnimationFrame(graphic, sync_frame);
+  }
+}
+
 void getGraphicSourceBitmap(int graphic, int tilesize, Bitmap **bitmap)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
@@ -1654,7 +1752,7 @@ void DrawGraphicThruMask(int x, int y, int graphic, int frame)
 #if DEBUG
   if (!IN_SCR_FIELD(x, y))
   {
-    Debug("draw:DrawGraphicThruMask", "x = %d,y = %d, graphic = %d",
+    Debug("draw:DrawGraphicThruMask", "x = %d, y = %d, graphic = %d",
          x, y, graphic);
     Debug("draw:DrawGraphicThruMask", "This should never happen!");
 
@@ -1673,7 +1771,7 @@ void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
 #if DEBUG
   if (!IN_SCR_FIELD(x, y))
   {
-    Debug("draw:DrawFixedGraphicThruMask", "x = %d,y = %d, graphic = %d",
+    Debug("draw:DrawFixedGraphicThruMask", "x = %d, y = %d, graphic = %d",
          x, y, graphic);
     Debug("draw:DrawFixedGraphicThruMask", "This should never happen!");
 
@@ -1747,7 +1845,7 @@ void DrawSizedGraphicThruMaskExt(DrawBuffer *d, int x, int y, int graphic,
 
 void DrawMiniGraphic(int x, int y, int graphic)
 {
-  DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
+  DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX, SY + y * MINI_TILEY, graphic);
   MarkTileDirty(x / 2, y / 2);
 }
 
@@ -1950,9 +2048,9 @@ static void DrawGraphicShifted(int x, int y, int dx, int dy,
   }
 
   if (graphic_info[graphic].double_movement)   // EM style movement images
-    DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
+    DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
   else
-    DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
+    DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
 }
 
 static void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy,
@@ -1970,16 +2068,19 @@ void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
 
   if (IN_LEV_FIELD(lx, ly))
   {
+    if (element == EL_EMPTY)
+      element = GfxElementEmpty[lx][ly];
+
     SetRandomAnimationValue(lx, ly);
 
     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
-    frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
+    frame = getGraphicAnimationFrameXY(graphic, lx, ly);
 
     // do not use double (EM style) movement graphic when not moving
     if (graphic_info[graphic].double_movement && !dx && !dy)
     {
       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
-      frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
+      frame = getGraphicAnimationFrameXY(graphic, lx, ly);
     }
 
     if (game.use_masked_elements && (dx || dy))
@@ -1988,7 +2089,7 @@ void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
   else // border element
   {
     graphic = el2img(element);
-    frame = getGraphicAnimationFrame(graphic, -1);
+    frame = getGraphicAnimationFrameXY(graphic, lx, ly);
   }
 
   if (element == EL_EXPANDABLE_WALL)
@@ -2105,7 +2206,7 @@ static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
   if (game.use_masked_elements)
   {
     int graphic0 = el2img(EL_EMPTY);
-    int frame0 = getGraphicAnimationFrame(graphic0, GfxFrame[x][y]);
+    int frame0 = getGraphicAnimationFrameXY(graphic0, x, y);
     Bitmap *src_bitmap0;
     int src_x0, src_y0;
 
@@ -2143,7 +2244,7 @@ static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
 
   // only needed when using masked elements
   int graphic0 = el2img(EL_EMPTY);
-  int frame0 = getGraphicAnimationFrame(graphic0, GfxFrame[x][y]);
+  int frame0 = getGraphicAnimationFrameXY(graphic0, x, y);
   Bitmap *src_bitmap0;
   int src_x0, src_y0;
 
@@ -2245,13 +2346,7 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
   int sx = SCREENX(x), sy = SCREENY(y);
   int element;
   int i;
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
 
   if (!IN_LEV_FIELD(x, y))
     return;
@@ -2266,8 +2361,8 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
     // crumble field borders towards direct neighbour fields
     for (i = 0; i < 4; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
                 BorderElement);
@@ -2301,10 +2396,10 @@ static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
     // crumble field borders of direct neighbour fields
     for (i = 0; i < 4; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
-      int sxx = sx + xy[i][0];
-      int syy = sy + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
+      int sxx = sx + xy[i].x;
+      int syy = sy + xy[i].y;
 
       if (!IN_LEV_FIELD(xx, yy) ||
          !IN_SCR_FIELD(sxx, syy))
@@ -2397,22 +2492,16 @@ void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
 void DrawLevelFieldCrumbledNeighbours(int x, int y)
 {
   int sx = SCREENX(x), sy = SCREENY(y);
-  static int xy[4][2] =
-  {
-    { 0, -1 },
-    { -1, 0 },
-    { +1, 0 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_topdown;
   int i;
 
   // crumble direct neighbour fields (required for field borders)
   for (i = 0; i < 4; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
-    int sxx = sx + xy[i][0];
-    int syy = sy + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
+    int sxx = sx + xy[i].x;
+    int syy = sy + xy[i].y;
 
     if (!IN_LEV_FIELD(xx, yy) ||
        !IN_SCR_FIELD(sxx, syy) ||
@@ -2486,6 +2575,11 @@ void DrawScreenGraphic(int x, int y, int graphic, int frame)
   }
 }
 
+void DrawLevelGraphic(int x, int y, int graphic, int frame)
+{
+  DrawScreenGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+}
+
 void DrawScreenElement(int x, int y, int element)
 {
   int mask_mode = NO_MASKING;
@@ -2641,7 +2735,7 @@ void DrawLevelField(int x, int y)
     DrawScreenField(SCREENX(x), SCREENY(y));
   else if (IS_MOVING(x, y))
   {
-    int newx,newy;
+    int newx, newy;
 
     Moving2Blocked(x, y, &newx, &newy);
     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
@@ -2724,12 +2818,14 @@ static void DrawSizedElementExt(int x, int y, int element, int tilesize,
   }
   else
   {
-    int graphic = el2edimg(element);
+    int graphic, frame;
+
+    el2edimg_with_frame(element, &graphic, &frame);
 
     if (masked)
-      DrawSizedGraphicThruMask(x, y, graphic, 0, tilesize);
+      DrawSizedGraphicThruMask(x, y, graphic, frame, tilesize);
     else
-      DrawSizedGraphic(x, y, graphic, 0, tilesize);
+      DrawSizedGraphic(x, y, graphic, frame, tilesize);
   }
 }
 
@@ -2833,9 +2929,9 @@ static void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
-  unsigned int anim_delay = 0;
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
   int anim_delay_value = MAX(1, (no_delay ? 0 : frame_delay_value) / 2);
+  DelayCounter anim_delay = { anim_delay_value };
   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
@@ -2872,16 +2968,16 @@ static void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
       for (xx = 0; xx < xsize; xx++)
        DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
 
-    DrawTextBuffer(sx + font_width, sy + font_height,
-                  level.envelope[envelope_nr].text, font_nr, max_xsize,
-                  xsize - 2, ysize - 2, 0, mask_mode,
-                  level.envelope[envelope_nr].autowrap,
-                  level.envelope[envelope_nr].centered, FALSE);
+    DrawTextArea(sx + font_width, sy + font_height,
+                level.envelope[envelope_nr].text, font_nr, max_xsize,
+                xsize - 2, ysize - 2, 0, mask_mode,
+                level.envelope[envelope_nr].autowrap,
+                level.envelope[envelope_nr].centered, FALSE);
 
     redraw_mask |= REDRAW_FIELD;
     BackToFront();
 
-    SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
+    SkipUntilDelayReached(&anim_delay, &i, last_frame);
   }
 
   ClearAutoRepeatKeyEvents();
@@ -2941,8 +3037,7 @@ void ShowEnvelope(int envelope_nr)
 static void PrepareEnvelopeRequestToScreen(Bitmap *bitmap, int sx, int sy,
                                           int xsize, int ysize)
 {
-  if (!global.use_envelope_request ||
-      request.sort_priority <= 0)
+  if (!global.use_envelope_request)
     return;
 
   if (request.bitmap == NULL ||
@@ -2962,9 +3057,22 @@ static void PrepareEnvelopeRequestToScreen(Bitmap *bitmap, int sx, int sy,
 
   BlitBitmap(bitmap, request.bitmap, sx, sy, xsize, ysize, 0, 0);
 
+  // create masked surface for request bitmap, if needed
+  if (graphic_info[IMG_BACKGROUND_REQUEST].draw_masked)
+  {
+    SDL_Surface *surface        = request.bitmap->surface;
+    SDL_Surface *surface_masked = request.bitmap->surface_masked;
+
+    SDLBlitSurface(surface, surface_masked, 0, 0, xsize, ysize, 0, 0);
+    SDL_SetColorKey(surface_masked, SET_TRANSPARENT_PIXEL,
+                   SDL_MapRGB(surface_masked->format, 0x00, 0x00, 0x00));
+  }
+
   SDLFreeBitmapTextures(request.bitmap);
   SDLCreateBitmapTextures(request.bitmap);
 
+  ResetBitmapAlpha(request.bitmap);
+
   // set envelope request run-time values
   request.sx = sx;
   request.sy = sy;
@@ -2972,16 +3080,22 @@ static void PrepareEnvelopeRequestToScreen(Bitmap *bitmap, int sx, int sy,
   request.ysize = ysize;
 }
 
-void DrawEnvelopeRequestToScreen(int drawing_target, int drawing_stage)
+void DrawEnvelopeRequestToScreen(int drawing_target)
 {
   if (global.use_envelope_request &&
-      game.request_active_or_moving &&
-      request.sort_priority > 0 &&
-      drawing_target == DRAW_TO_SCREEN &&
-      drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
+      game.request_active &&
+      drawing_target == DRAW_TO_SCREEN)
   {
-    BlitToScreen(request.bitmap, 0, 0, request.xsize, request.ysize,
-                request.sx, request.sy);
+    struct GraphicInfo *g = &graphic_info[IMG_BACKGROUND_REQUEST];
+
+    SetBitmapAlphaNextBlit(request.bitmap, g->alpha);
+
+    if (g->draw_masked)
+      BlitToScreenMasked(request.bitmap, 0, 0, request.xsize, request.ysize,
+                        request.sx, request.sy);
+    else
+      BlitToScreen(request.bitmap, 0, 0, request.xsize, request.ysize,
+                  request.sx, request.sy);
   }
 }
 
@@ -3052,7 +3166,7 @@ static void setRequestPosition(int *x, int *y, boolean add_border_size)
   setRequestPositionExt(x, y, request.width, request.height, add_border_size);
 }
 
-static void DrawEnvelopeRequest(char *text)
+static void DrawEnvelopeRequestText(int sx, int sy, char *text)
 {
   char *text_final = text;
   char *text_door_style = NULL;
@@ -3070,15 +3184,11 @@ static void DrawEnvelopeRequest(char *text)
   int line_length = max_text_width  / font_width;
   int max_lines   = max_text_height / line_height;
   int text_width = line_length * font_width;
-  int width = request.width;
-  int height = request.height;
-  int tile_size = MAX(request.step_offset, 1);
-  int x_steps = width  / tile_size;
-  int y_steps = height / tile_size;
   int sx_offset = border_size;
   int sy_offset = border_size;
-  int sx, sy;
-  int i, x, y;
+
+  // force DOOR font inside door area
+  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
 
   if (request.centered)
     sx_offset = (request.width - text_width) / 2;
@@ -3087,6 +3197,13 @@ static void DrawEnvelopeRequest(char *text)
   {
     char *src_text_ptr, *dst_text_ptr;
 
+    if (maxWordLengthInRequestString(text) > line_length)
+    {
+      font_nr = FONT_REQUEST_NARROW;
+      font_width = getFontWidth(font_nr);
+      line_length = max_text_width  / font_width;
+    }
+
     text_door_style = checked_malloc(2 * strlen(text) + 1);
 
     src_text_ptr = text;
@@ -3110,9 +3227,34 @@ static void DrawEnvelopeRequest(char *text)
     text_final = text_door_style;
   }
 
+  DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
+                line_length, -1, max_lines, line_spacing, mask_mode,
+                request.autowrap, request.centered, FALSE);
+
+  if (text_door_style)
+    free(text_door_style);
+
+  ResetFontStatus();
+}
+
+static void DrawEnvelopeRequest(char *text, unsigned int req_state)
+{
+  DrawBuffer *drawto_last = drawto;
+  int graphic = IMG_BACKGROUND_REQUEST;
+  int width = request.width;
+  int height = request.height;
+  int tile_size = MAX(request.step_offset, 1);
+  int x_steps = width  / tile_size;
+  int y_steps = height / tile_size;
+  int sx, sy;
+  int x, y;
+
   setRequestPosition(&sx, &sy, FALSE);
 
-  ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+  // draw complete envelope request to temporary bitmap
+  drawto = bitmap_db_store_1;
+
+  ClearRectangle(drawto, sx, sy, width, height);
 
   for (y = 0; y < y_steps; y++)
     for (x = 0; x < x_steps; x++)
@@ -3120,38 +3262,28 @@ static void DrawEnvelopeRequest(char *text)
                                  x, y, x_steps, y_steps,
                                  tile_size, tile_size);
 
-  // force DOOR font inside door area
-  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
-
-  DrawTextBuffer(sx + sx_offset, sy + sy_offset, text_final, font_nr,
-                line_length, -1, max_lines, line_spacing, mask_mode,
-                request.autowrap, request.centered, FALSE);
-
-  ResetFontStatus();
-
-  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
-    RedrawGadget(tool_gadget[i]);
+  // write text for request
+  DrawEnvelopeRequestText(sx, sy, text);
 
-  // store readily prepared envelope request for later use when animating
-  BlitBitmap(backbuffer, bitmap_db_store_2, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  MapToolButtons(req_state);
 
-  PrepareEnvelopeRequestToScreen(bitmap_db_store_2, sx, sy, width, height);
+  // restore pointer to drawing buffer
+  drawto = drawto_last;
 
-  if (text_door_style)
-    free(text_door_style);
+  // prepare complete envelope request from temporary bitmap
+  PrepareEnvelopeRequestToScreen(bitmap_db_store_1, sx, sy, width, height);
 }
 
 static void AnimateEnvelopeRequest(int anim_mode, int action)
 {
-  int graphic = IMG_BACKGROUND_REQUEST;
-  boolean draw_masked = graphic_info[graphic].draw_masked;
+  boolean game_ended = (game_status == GAME_MODE_PLAYING && checkGameEnded());
   int delay_value_normal = request.step_delay;
   int delay_value_fast = delay_value_normal / 2;
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
-  int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value + 500 * 0) / 2);
-  unsigned int anim_delay = 0;
+  int anim_delay_value = MAX(1, (no_delay ? 0 : delay_value) / 2);
+  DelayCounter anim_delay = { anim_delay_value };
 
   int tile_size = MAX(request.step_offset, 1);
   int max_xsize = request.width  / tile_size;
@@ -3193,11 +3325,12 @@ static void AnimateEnvelopeRequest(int anim_mode, int action)
     int dst_x, dst_y;
     int xx, yy;
 
+    if (game_ended)
+      HandleGameActions();
+
     setRequestPosition(&src_x, &src_y, FALSE);
     setRequestPositionExt(&dst_x, &dst_y, width, height, FALSE);
 
-    BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-
     for (yy = 0; yy < 2; yy++)
     {
       for (xx = 0; xx < 2; xx++)
@@ -3209,22 +3342,21 @@ static void AnimateEnvelopeRequest(int anim_mode, int action)
        int xx_size = (xx ? tile_size : xsize_size_left);
        int yy_size = (yy ? tile_size : ysize_size_top);
 
-       if (draw_masked)
-         BlitBitmapMasked(bitmap_db_store_2, backbuffer,
-                          src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
-       else
-         BlitBitmap(bitmap_db_store_2, backbuffer,
-                    src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
+       // draw partial (animated) envelope request to temporary bitmap
+       BlitBitmap(bitmap_db_store_1, bitmap_db_store_2,
+                  src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
       }
     }
 
-    PrepareEnvelopeRequestToScreen(backbuffer, dst_x, dst_y, width, height);
+    // prepare partial (animated) envelope request from temporary bitmap
+    PrepareEnvelopeRequestToScreen(bitmap_db_store_2, dst_x, dst_y,
+                                  width, height);
 
     redraw_mask |= REDRAW_FIELD;
 
     BackToFront();
 
-    SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
+    SkipUntilDelayReached(&anim_delay, &i, last_frame);
   }
 
   ClearAutoRepeatKeyEvents();
@@ -3241,40 +3373,6 @@ static void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
                        anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
 
-  if (game_status == GAME_MODE_PLAYING)
-    BlitScreenToBitmap(backbuffer);
-
-  SetDrawtoField(DRAW_TO_BACKBUFFER);
-
-  // SetDrawBackgroundMask(REDRAW_NONE);
-
-  if (action == ACTION_OPENING)
-  {
-    BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-
-    if (req_state & REQ_ASK)
-    {
-      MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_YES]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_NO]);
-    }
-    else if (req_state & REQ_CONFIRM)
-    {
-      MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_CONFIRM]);
-    }
-    else if (req_state & REQ_PLAYER)
-    {
-      MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
-      MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
-    }
-
-    DrawEnvelopeRequest(text);
-  }
-
   game.envelope_active = TRUE; // needed for RedrawPlayfield() events
 
   if (action == ACTION_OPENING)
@@ -3298,20 +3396,14 @@ static void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
   }
 
   game.envelope_active = FALSE;
+}
 
-  if (action == ACTION_CLOSING)
-    BlitBitmap(bitmap_db_store_1, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-
-  // SetDrawBackgroundMask(last_draw_background_mask);
-
-  redraw_mask |= REDRAW_FIELD;
-
-  BackToFront();
+static Bitmap *GetPreviewTileBitmap(Bitmap *bitmap)
+{
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    return GetPreviewTileBitmap_BD(bitmap);
 
-  if (action == ACTION_CLOSING &&
-      game_status == GAME_MODE_PLAYING &&
-      level.game_engine_type == GAME_ENGINE_TYPE_RND)
-    SetDrawtoField(DRAW_TO_FIELDBUFFER);
+  return bitmap;
 }
 
 static void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
@@ -3327,6 +3419,10 @@ static void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
     int graphic = el2preimg(element);
 
     getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
+
+    // for BD style levels, maybe use bitmap with level-specific colors
+    src_bitmap = GetPreviewTileBitmap(src_bitmap);
+
     BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize,
               dst_x, dst_y);
   }
@@ -3334,7 +3430,7 @@ static void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
 
 void DrawLevel(int draw_background_mask)
 {
-  int x,y;
+  int x, y;
 
   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
   SetDrawBackgroundMask(draw_background_mask);
@@ -3351,7 +3447,7 @@ void DrawLevel(int draw_background_mask)
 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
                    int tilesize)
 {
-  int x,y;
+  int x, y;
 
   for (x = 0; x < size_x; x++)
     for (y = 0; y < size_y; y++)
@@ -3362,7 +3458,7 @@ void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
 
 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
 {
-  int x,y;
+  int x, y;
 
   for (x = 0; x < size_x; x++)
     for (y = 0; y < size_y; y++)
@@ -3371,11 +3467,27 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
   redraw_mask |= REDRAW_FIELD;
 }
 
+static int getPreviewLevelWidth(void)
+{
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    return (level.native_bd_level->cave->x2 - level.native_bd_level->cave->x1 + 1);
+
+  return lev_fieldx;
+}
+
+static int getPreviewLevelHeight(void)
+{
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    return (level.native_bd_level->cave->y2 - level.native_bd_level->cave->y1 + 1);
+
+  return lev_fieldy;
+}
+
 static void DrawPreviewLevelPlayfield(int from_x, int from_y)
 {
   boolean show_level_border = (BorderElement != EL_EMPTY);
-  int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
-  int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
+  int level_xsize = getPreviewLevelWidth()  + (show_level_border ? 2 : 0);
+  int level_ysize = getPreviewLevelHeight() + (show_level_border ? 2 : 0);
   int tile_size = preview.tile_size;
   int preview_width  = preview.xsize * tile_size;
   int preview_height = preview.ysize * tile_size;
@@ -3495,15 +3607,17 @@ static void DrawPreviewLevelInfo(int mode)
 
 static void DrawPreviewLevelExt(boolean restart)
 {
-  static unsigned int scroll_delay = 0;
-  static unsigned int label_delay = 0;
+  static DelayCounter scroll_delay = { 0 };
+  static DelayCounter label_delay = { 0 };
   static int from_x, from_y, scroll_direction;
   static int label_state, label_counter;
-  unsigned int scroll_delay_value = preview.step_delay;
   boolean show_level_border = (BorderElement != EL_EMPTY);
   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
 
+  scroll_delay.value = preview.step_delay;
+  label_delay.value = MICROLEVEL_LABEL_DELAY;
+
   if (restart)
   {
     from_x = 0;
@@ -3557,7 +3671,7 @@ static void DrawPreviewLevelExt(boolean restart)
   // scroll preview level, if needed
   if (preview.anim_mode != ANIM_NONE &&
       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
-      DelayReached(&scroll_delay, scroll_delay_value))
+      DelayReached(&scroll_delay))
   {
     switch (scroll_direction)
     {
@@ -3615,7 +3729,7 @@ static void DrawPreviewLevelExt(boolean restart)
   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
       !strEqual(level.author, ANONYMOUS_NAME) &&
       !strEqual(level.author, leveldir_current->name) &&
-      DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
+      DelayReached(&label_delay))
   {
     int max_label_counter = 23;
 
@@ -3731,8 +3845,35 @@ void DrawPreviewPlayers(void)
   }
 }
 
+static void PreparePreviewTileBitmap(void)
+{
+  // check if special preview bitmap with level-specific colors should be created
+  if (level.game_engine_type != GAME_ENGINE_TYPE_BD)
+    return;
+
+  // use original sized bitmap (else reduced color palette is lost by downscaling)
+  int original_tilesize = MAX(MINI_TILESIZE, preview.tile_size);
+  int scale_down_factor = original_tilesize / preview.tile_size;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int element_template = EL_BDX_GAME_GRAPHICS_COLOR_TEMPLATE;
+  int graphic_template = el2preimg(element_template);
+  int element_default = EL_BDX_ROCK;
+  int graphic_default = el2preimg(element_default);
+
+  // create special preview bitmap and scale it down to preview tile size
+  getSizedGraphicSource(graphic_template, 0, original_tilesize, &src_bitmap, &src_x, &src_y);
+  PreparePreviewTileBitmap_BD(src_bitmap, scale_down_factor);
+
+  // force using special preview bitmap to replace original preview bitmap
+  getSizedGraphicSource(graphic_default, 0, preview.tile_size, &src_bitmap, &src_x, &src_y);
+  SetPreviewTileBitmapReference_BD(src_bitmap);
+}
+
 void DrawPreviewLevelInitial(void)
 {
+  PreparePreviewTileBitmap();  // only needed for native BD style levels
+
   DrawPreviewLevelExt(TRUE);
   DrawPreviewPlayers();
 }
@@ -3840,10 +3981,10 @@ void ClearNetworkPlayers(void)
 }
 
 static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
-                                   int graphic, int sync_frame,
+                                   int graphic, int lx, int ly,
                                    int mask_mode)
 {
-  int frame = getGraphicAnimationFrame(graphic, sync_frame);
+  int frame = getGraphicAnimationFrameXY(graphic, lx, ly);
 
   if (mask_mode == USE_MASKING)
     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
@@ -3862,6 +4003,18 @@ void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
 }
 
+void DrawSizedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+                                 int graphic, int sync_frame, int tilesize,
+                                 int mask_mode)
+{
+  int frame = getGraphicAnimationFrame(graphic, sync_frame);
+
+  if (mask_mode == USE_MASKING)
+    DrawSizedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame, tilesize);
+  else
+    DrawSizedGraphicExt(dst_bitmap, x, y, graphic, frame, tilesize);
+}
+
 static void DrawGraphicAnimation(int x, int y, int graphic)
 {
   int lx = LEVELX(x), ly = LEVELY(y);
@@ -3881,7 +4034,7 @@ static void DrawGraphicAnimation(int x, int y, int graphic)
   }
 
   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
-                         graphic, GfxFrame[lx][ly], mask_mode);
+                         graphic, lx, ly, mask_mode);
 
   MarkTileDirty(x, y);
 }
@@ -3905,7 +4058,7 @@ void DrawFixedGraphicAnimation(int x, int y, int graphic)
   }
 
   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
-                         graphic, GfxFrame[lx][ly], mask_mode);
+                         graphic, lx, ly, mask_mode);
 
   MarkTileDirty(x, y);
 }
@@ -3929,9 +4082,15 @@ void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
     return;
 
+  if (Tile[x][y] == EL_EMPTY)
+    graphic = el2img(GfxElementEmpty[x][y]);
+
   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
     return;
 
+  if (ANIM_MODE(graphic) & (ANIM_TILED | ANIM_RANDOM_STATIC))
+    return;
+
   DrawGraphicAnimation(sx, sy, graphic);
 
 #if 1
@@ -3983,7 +4142,7 @@ static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
     return graphic;
   }
   else
-    return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
+    return el_act_dir2img(player->artwork_element, player->GfxAction, move_dir);
 }
 
 static boolean equalGraphics(int graphic1, int graphic2)
@@ -4132,9 +4291,6 @@ static void DrawPlayerExt(struct PlayerInfo *player, int drawing_stage)
       DrawDynamite(last_jx, last_jy);
     else
       DrawLevelField(last_jx, last_jy);
-
-    if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
-      DrawLevelElement(next_jx, next_jy, EL_EMPTY);
   }
   else if (drawing_stage == DRAW_PLAYER_STAGE_FIELD_UNDER_PLAYER)
   {
@@ -4192,6 +4348,9 @@ static void DrawPlayerExt(struct PlayerInfo *player, int drawing_stage)
     if (!player->is_pushing || !player->is_moving)
       return;
 
+    if (Tile[next_jx][next_jy] == EL_EXPLOSION)
+      return;
+
     int gfx_frame = GfxFrame[jx][jy];
 
     if (!IS_MOVING(jx, jy))            // push movement already finished
@@ -4213,14 +4372,12 @@ static void DrawPlayerExt(struct PlayerInfo *player, int drawing_stage)
        DrawLevelElement(jx, jy, Back[jx][jy]);
       else
        DrawLevelElement(jx, jy, EL_EMPTY);
-
-      if (Back[next_jx][next_jy])
-       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
-      else
-       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
     }
-    else if (Back[next_jx][next_jy])
+
+    if (Back[next_jx][next_jy])
       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+    else
+      DrawLevelElement(next_jx, next_jy, EL_EMPTY);
 
     int px = SCREENX(jx), py = SCREENY(jy);
     int pxx = (TILEX - ABS(sxx)) * dx;
@@ -4277,7 +4434,7 @@ static void DrawPlayerExt(struct PlayerInfo *player, int drawing_stage)
     if (IS_ACTIVE_BOMB(element))
     {
       int graphic = el2img(element);
-      int frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
+      int frame = getGraphicAnimationFrameXY(graphic, jx, jy);
 
       if (game.emulation == EMU_SUPAPLEX)
        DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
@@ -4411,26 +4568,15 @@ void WaitForEventToContinue(void)
   }
 }
 
-#define MAX_REQUEST_LINES              13
-#define MAX_REQUEST_LINE_FONT1_LEN     7
-#define MAX_REQUEST_LINE_FONT2_LEN     10
-
 static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
 {
-  boolean game_just_ended = (game_status == GAME_MODE_PLAYING &&
-                            checkGameEnded());
+  boolean game_ended = (game_status == GAME_MODE_PLAYING && checkGameEnded());
   int draw_buffer_last = GetDrawtoField();
   int width  = request.width;
   int height = request.height;
   int sx, sy;
   int result;
 
-  // when showing request dialog after game ended, deactivate game panel
-  if (game_just_ended)
-    game.panel.active = FALSE;
-
-  game.request_active = TRUE;
-
   setRequestPosition(&sx, &sy, FALSE);
 
   button_status = MB_RELEASED;
@@ -4440,21 +4586,13 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
 
   while (result < 0)
   {
-    boolean event_handled = FALSE;
-
-    if (game_just_ended)
+    if (game_ended)
     {
       SetDrawtoField(draw_buffer_game);
 
       HandleGameActions();
 
       SetDrawtoField(DRAW_TO_BACKBUFFER);
-
-      if (global.use_envelope_request)
-      {
-       // copy current state of request area to middle of playfield area
-       BlitBitmap(bitmap_db_store_2, drawto, sx, sy, width, height, sx, sy);
-      }
     }
 
     if (PendingEvent())
@@ -4463,14 +4601,13 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
 
       while (NextValidEvent(&event))
       {
-       event_handled = TRUE;
-
        switch (event.type)
        {
          case EVENT_BUTTONPRESS:
          case EVENT_BUTTONRELEASE:
          case EVENT_MOTIONNOTIFY:
          {
+           DrawBuffer *drawto_last = drawto;
            int mx, my;
 
            if (event.type == EVENT_MOTIONNOTIFY)
@@ -4493,9 +4630,25 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
                button_status = MB_RELEASED;
            }
 
+           if (global.use_envelope_request)
+           {
+             // draw changed button states to temporary bitmap
+             drawto = bitmap_db_store_1;
+           }
+
            // this sets 'request_gadget_id'
            HandleGadgets(mx, my, button_status);
 
+           if (global.use_envelope_request)
+           {
+             // restore pointer to drawing buffer
+             drawto = drawto_last;
+
+             // prepare complete envelope request from temporary bitmap
+             PrepareEnvelopeRequestToScreen(bitmap_db_store_1, sx, sy,
+                                            width, height);
+           }
+
            switch (request_gadget_id)
            {
              case TOOL_CTRL_ID_YES:
@@ -4525,11 +4678,12 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
                break;
 
              default:
-               // only check clickable animations if no request gadget clicked
-               HandleGlobalAnimClicks(mx, my, button_status, FALSE);
                break;
            }
 
+           // only needed to handle clickable pointer animations here
+           HandleGlobalAnimClicks(mx, my, button_status, FALSE);
+
            break;
          }
 
@@ -4546,7 +4700,7 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
 
          case EVENT_KEYPRESS:
          {
-           Key key = GetEventKey((KeyEvent *)&event, TRUE);
+           Key key = GetEventKey((KeyEvent *)&event);
 
            switch (key)
            {
@@ -4719,45 +4873,21 @@ static int RequestHandleEvents(unsigned int req_state, int draw_buffer_game)
       }
     }
 
-    if (event_handled)
-    {
-      if (game_just_ended)
-      {
-       if (global.use_envelope_request)
-       {
-         // copy back current state of pressed buttons inside request area
-         BlitBitmap(drawto, bitmap_db_store_2, sx, sy, width, height, sx, sy);
-       }
-      }
-
-      PrepareEnvelopeRequestToScreen(drawto, sx, sy, width, height);
-    }
-
     BackToFront();
   }
 
   SetDrawtoField(draw_buffer_last);
 
-  game.request_active = FALSE;
-
   return result;
 }
 
-static boolean RequestDoor(char *text, unsigned int req_state)
+static void DoRequestBefore(void)
 {
-  int draw_buffer_last = GetDrawtoField();
-  unsigned int old_door_state;
-  int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
-  int font_nr = FONT_TEXT_2;
-  char *text_ptr;
-  int result;
-  int ty;
+  boolean game_ended = (game_status == GAME_MODE_PLAYING && checkGameEnded());
 
-  if (maxWordLengthInRequestString(text) > MAX_REQUEST_LINE_FONT1_LEN)
-  {
-    max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
-    font_nr = FONT_TEXT_1;
-  }
+  // when showing request dialog after game ended, deactivate game panel
+  if (game_ended)
+    game.panel.active = FALSE;
 
   if (game_status == GAME_MODE_PLAYING)
     BlitScreenToBitmap(backbuffer);
@@ -4771,52 +4901,99 @@ static boolean RequestDoor(char *text, unsigned int req_state)
   // pause network game while waiting for request to answer
   if (network.enabled &&
       game_status == GAME_MODE_PLAYING &&
-      !game.all_players_gone &&
-      req_state & REQUEST_WAIT_FOR_INPUT)
+      !game.all_players_gone)
     SendToServer_PausePlaying();
 
-  old_door_state = GetDoorState();
-
   // simulate releasing mouse button over last gadget, if still pressed
   if (button_status)
     HandleGadgets(-1, -1, 0);
 
   UnmapAllGadgets();
+}
 
-  // draw released gadget before proceeding
-  // BackToFront();
+static void DoRequestAfter(void)
+{
+  RemapAllGadgets();
 
-  if (old_door_state & DOOR_OPEN_1)
+  if (game_status == GAME_MODE_PLAYING)
   {
-    CloseDoor(DOOR_CLOSE_1);
-
-    // save old door content
-    BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
-              0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
+    SetPanelBackground();
+    SetDrawBackgroundMask(REDRAW_DOOR_1);
   }
-
-  SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
-  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
-
-  // clear door drawing field
-  DrawBackground(DX, DY, DXSIZE, DYSIZE);
-
-  // force DOOR font inside door area
-  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
-
-  // write text for request
-  for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
+  else
   {
-    char text_line[max_request_line_len + 1];
-    int tx, tl, tc = 0;
+    SetDrawBackgroundMask(REDRAW_FIELD);
+  }
 
-    if (!*text_ptr)
-      break;
+  // continue network game after request
+  if (network.enabled &&
+      game_status == GAME_MODE_PLAYING &&
+      !game.all_players_gone)
+    SendToServer_ContinuePlaying();
+
+  // restore deactivated drawing when quick-loading level tape recording
+  if (tape.playing && tape.deactivate_display)
+    TapeDeactivateDisplayOn();
+}
+
+static void setRequestDoorTextProperties(char *text,
+                                        int text_spacing,
+                                        int line_spacing,
+                                        int *set_font_nr,
+                                        int *set_max_lines,
+                                        int *set_max_line_length)
+{
+  struct RectWithBorder *vp_door_1 = &viewport.door_1[game_status];
+  struct TextPosInfo *pos = &request.button.confirm;
+  int button_ypos = pos->y;
+  int font_nr = FONT_TEXT_2;
+  int font_width = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  int line_height = font_height + line_spacing;
+  int max_text_width  = vp_door_1->width;
+  int max_text_height = button_ypos - 2 * text_spacing;
+  int max_line_length = max_text_width  / font_width;
+  int max_lines       = max_text_height / line_height;
+
+  if (maxWordLengthInRequestString(text) > max_line_length)
+  {
+    font_nr = FONT_TEXT_1;
+    font_width = getFontWidth(font_nr);
+    max_line_length = max_text_width  / font_width;
+  }
+
+  *set_font_nr = font_nr;
+  *set_max_lines = max_lines;
+  *set_max_line_length = max_line_length;
+}
+
+static void DrawRequestDoorText(char *text)
+{
+  char *text_ptr = text;
+  int text_spacing = 8;
+  int line_spacing = 2;
+  int max_request_lines;
+  int max_request_line_len;
+  int font_nr;
+  int ty;
+
+  // force DOOR font inside door area
+  SetFontStatus(GAME_MODE_PSEUDO_DOOR);
+
+  setRequestDoorTextProperties(text, text_spacing, line_spacing, &font_nr,
+                              &max_request_lines, &max_request_line_len);
+
+  for (text_ptr = text, ty = 0; ty < max_request_lines; ty++)
+  {
+    char text_line[max_request_line_len + 1];
+    int tx, tl, tc = 0;
+
+    if (!*text_ptr)
+      break;
 
     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
     {
       tc = *(text_ptr + tx);
-      // if (!tc || tc == ' ')
       if (!tc || tc == ' ' || tc == '?' || tc == '!')
        break;
     }
@@ -4835,56 +5012,45 @@ static boolean RequestDoor(char *text, unsigned int req_state)
     text_line[tl] = 0;
 
     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
-            DY + 8 + ty * (getFontHeight(font_nr) + 2),
+            DY + text_spacing + ty * (getFontHeight(font_nr) + line_spacing),
             text_line, font_nr);
 
     text_ptr += tl + (tc == ' ' ? 1 : 0);
-    // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
   }
 
   ResetFontStatus();
+}
 
-  if (req_state & REQ_ASK)
-  {
-    MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_YES]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_NO]);
-  }
-  else if (req_state & REQ_CONFIRM)
-  {
-    MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_CONFIRM]);
-  }
-  else if (req_state & REQ_PLAYER)
+static int RequestDoor(char *text, unsigned int req_state)
+{
+  unsigned int old_door_state = GetDoorState();
+  int draw_buffer_last = GetDrawtoField();
+  int result;
+
+  if (old_door_state & DOOR_OPEN_1)
   {
-    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
-    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
+    CloseDoor(DOOR_CLOSE_1);
+
+    // save old door content
+    BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
+              0, 0, DXSIZE, DYSIZE, DXSIZE, 0);
   }
 
-  // copy request gadgets to door backbuffer
-  BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
+  SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
 
-  OpenDoor(DOOR_OPEN_1);
+  // clear door drawing field
+  DrawBackground(DX, DY, DXSIZE, DYSIZE);
 
-  if (!(req_state & REQUEST_WAIT_FOR_INPUT))
-  {
-    if (game_status == GAME_MODE_PLAYING)
-    {
-      SetPanelBackground();
-      SetDrawBackgroundMask(REDRAW_DOOR_1);
-    }
-    else
-    {
-      SetDrawBackgroundMask(REDRAW_FIELD);
-    }
+  // write text for request
+  DrawRequestDoorText(text);
 
-    return FALSE;
-  }
+  MapToolButtons(req_state);
 
-  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+  // copy request gadgets to door backbuffer
+  BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
+
+  OpenDoor(DOOR_OPEN_1);
 
   // ---------- handle request buttons ----------
   result = RequestHandleEvents(req_state, draw_buffer_last);
@@ -4900,85 +5066,17 @@ static boolean RequestDoor(char *text, unsigned int req_state)
       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
   }
 
-  RemapAllGadgets();
-
-  if (game_status == GAME_MODE_PLAYING)
-  {
-    SetPanelBackground();
-    SetDrawBackgroundMask(REDRAW_DOOR_1);
-  }
-  else
-  {
-    SetDrawBackgroundMask(REDRAW_FIELD);
-  }
-
-  // continue network game after request
-  if (network.enabled &&
-      game_status == GAME_MODE_PLAYING &&
-      !game.all_players_gone &&
-      req_state & REQUEST_WAIT_FOR_INPUT)
-    SendToServer_ContinuePlaying();
-
-  // restore deactivated drawing when quick-loading level tape recording
-  if (tape.playing && tape.deactivate_display)
-    TapeDeactivateDisplayOn();
-
   return result;
 }
 
-static boolean RequestEnvelope(char *text, unsigned int req_state)
+static int RequestEnvelope(char *text, unsigned int req_state)
 {
   int draw_buffer_last = GetDrawtoField();
   int result;
 
-  if (game_status == GAME_MODE_PLAYING)
-    BlitScreenToBitmap(backbuffer);
-
-  // disable deactivated drawing when quick-loading level tape recording
-  if (tape.playing && tape.deactivate_display)
-    TapeDeactivateDisplayOff(TRUE);
-
-  SetMouseCursor(CURSOR_DEFAULT);
-
-  // pause network game while waiting for request to answer
-  if (network.enabled &&
-      game_status == GAME_MODE_PLAYING &&
-      !game.all_players_gone &&
-      req_state & REQUEST_WAIT_FOR_INPUT)
-    SendToServer_PausePlaying();
-
-  // simulate releasing mouse button over last gadget, if still pressed
-  if (button_status)
-    HandleGadgets(-1, -1, 0);
-
-  UnmapAllGadgets();
-
-  // (replace with setting corresponding request background)
-  // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
-  // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
-
-  // clear door drawing field
-  // DrawBackground(DX, DY, DXSIZE, DYSIZE);
-
+  DrawEnvelopeRequest(text, req_state);
   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
 
-  if (!(req_state & REQUEST_WAIT_FOR_INPUT))
-  {
-    if (game_status == GAME_MODE_PLAYING)
-    {
-      SetPanelBackground();
-      SetDrawBackgroundMask(REDRAW_DOOR_1);
-    }
-    else
-    {
-      SetDrawBackgroundMask(REDRAW_FIELD);
-    }
-
-    return FALSE;
-  }
-
-  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
-
   // ---------- handle request buttons ----------
   result = RequestHandleEvents(req_state, draw_buffer_last);
 
@@ -4986,49 +5084,30 @@ static boolean RequestEnvelope(char *text, unsigned int req_state)
 
   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
 
-  RemapAllGadgets();
-
-  if (game_status == GAME_MODE_PLAYING)
-  {
-    SetPanelBackground();
-    SetDrawBackgroundMask(REDRAW_DOOR_1);
-  }
-  else
-  {
-    SetDrawBackgroundMask(REDRAW_FIELD);
-  }
-
-  // continue network game after request
-  if (network.enabled &&
-      game_status == GAME_MODE_PLAYING &&
-      !game.all_players_gone &&
-      req_state & REQUEST_WAIT_FOR_INPUT)
-    SendToServer_ContinuePlaying();
-
-  // restore deactivated drawing when quick-loading level tape recording
-  if (tape.playing && tape.deactivate_display)
-    TapeDeactivateDisplayOn();
-
   return result;
 }
 
-boolean Request(char *text, unsigned int req_state)
+int Request(char *text, unsigned int req_state)
 {
   boolean overlay_enabled = GetOverlayEnabled();
-  boolean result;
+  int result;
 
-  game.request_active_or_moving = TRUE;
+  game.request_active = TRUE;
 
   SetOverlayEnabled(FALSE);
 
+  DoRequestBefore();
+
   if (global.use_envelope_request)
     result = RequestEnvelope(text, req_state);
   else
     result = RequestDoor(text, req_state);
 
+  DoRequestAfter();
+
   SetOverlayEnabled(overlay_enabled);
 
-  game.request_active_or_moving = FALSE;
+  game.request_active = FALSE;
 
   return result;
 }
@@ -5293,8 +5372,7 @@ unsigned int MoveDoor(unsigned int door_state)
   };
   static int door1 = DOOR_CLOSE_1;
   static int door2 = DOOR_CLOSE_2;
-  unsigned int door_delay = 0;
-  unsigned int door_delay_value;
+  DelayCounter door_delay = { 0 };
   int i;
 
   if (door_state == DOOR_GET_STATE)
@@ -5333,6 +5411,7 @@ unsigned int MoveDoor(unsigned int door_state)
 
   if (door_state & DOOR_ACTION)
   {
+    boolean game_ended = (game_status == GAME_MODE_PLAYING && checkGameEnded());
     boolean door_panel_drawn[NUM_DOORS];
     boolean panel_has_doors[NUM_DOORS];
     boolean door_part_skip[MAX_DOOR_PARTS];
@@ -5344,7 +5423,6 @@ unsigned int MoveDoor(unsigned int door_state)
     int num_move_steps = 0;    // number of animation steps for all doors
     int max_move_delay_doors_only = 0; // delay for doors only (no panel)
     int num_move_steps_doors_only = 0; // steps for doors only (no panel)
-    int current_move_delay = 0;
     int start = 0;
     int k;
 
@@ -5410,7 +5488,7 @@ unsigned int MoveDoor(unsigned int door_state)
     num_move_steps = max_move_delay / max_step_delay;
     num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
 
-    door_delay_value = max_step_delay;
+    door_delay.value = max_step_delay;
 
     if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
     {
@@ -5439,6 +5517,10 @@ unsigned int MoveDoor(unsigned int door_state)
       }
     }
 
+    SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+
+    game.any_door_active = TRUE;
+
     for (k = start; k < num_move_steps; k++)
     {
       int last_frame = num_move_steps - 1;     // last frame of this "for" loop
@@ -5493,7 +5575,7 @@ unsigned int MoveDoor(unsigned int door_state)
        {
          int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
          int kk_door = MAX(0, k2_door);
-         int sync_frame = kk_door * door_delay_value;
+         int sync_frame = kk_door * door_delay.value;
          int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
 
          getFixedGraphicSource(dpc->graphic, frame, &bitmap,
@@ -5504,8 +5586,8 @@ unsigned int MoveDoor(unsigned int door_state)
 
        if (!door_panel_drawn[door_index])
        {
-         ClearRectangle(drawto, door_rect->x, door_rect->y,
-                        door_rect->width, door_rect->height);
+         ClearRectangleOnBackground(drawto, door_rect->x, door_rect->y,
+                                    door_rect->width, door_rect->height);
 
          door_panel_drawn[door_index] = TRUE;
        }
@@ -5600,11 +5682,12 @@ unsigned int MoveDoor(unsigned int door_state)
 
       if (!(door_state & DOOR_NO_DELAY))
       {
-       BackToFront();
+       if (game_ended)
+         HandleGameActions();
 
-       SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
+       BackToFront();
 
-       current_move_delay += max_step_delay;
+       SkipUntilDelayReached(&door_delay, &k, last_frame);
 
        // prevent OS (Windows) from complaining about program not responding
        CheckQuitEvent();
@@ -5618,15 +5701,22 @@ unsigned int MoveDoor(unsigned int door_state)
     {
       // wait for specified door action post delay
       if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
-       door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
+       door_delay.value = MAX(door_1.post_delay, door_2.post_delay);
       else if (door_state & DOOR_ACTION_1)
-       door_delay_value = door_1.post_delay;
+       door_delay.value = door_1.post_delay;
       else if (door_state & DOOR_ACTION_2)
-       door_delay_value = door_2.post_delay;
+       door_delay.value = door_2.post_delay;
+
+      while (!DelayReached(&door_delay))
+      {
+       if (game_ended)
+         HandleGameActions();
 
-      while (!DelayReached(&door_delay, door_delay_value))
        BackToFront();
+      }
     }
+
+    game.any_door_active = FALSE;
   }
 
   if (door_state & DOOR_ACTION_1)
@@ -5801,6 +5891,10 @@ void CreateToolButtons(void)
     int y = pos->y;
     int id = i;
 
+    // do not use touch buttons if overlay touch buttons are disabled
+    if (is_touch_button && !setup.touch.overlay_buttons)
+      continue;
+
     if (global.use_envelope_request && !is_touch_button)
     {
       setRequestPosition(&base_x, &base_y, TRUE);
@@ -5837,63 +5931,1799 @@ void CreateToolButtons(void)
       }
     }
 
-    if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
+    if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4 &&
+       pos->draw_player)
+    {
+      int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+
+      getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
+                           pos->size, &deco_bitmap, &deco_x, &deco_y);
+      deco_xpos = (gfx->width  - pos->size) / 2;
+      deco_ypos = (gfx->height - pos->size) / 2;
+    }
+
+    gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_IMAGE_ID, graphic,
+                     GDI_INFO_TEXT, toolbutton_info[i].infotext,
+                     GDI_X, base_x + x,
+                     GDI_Y, base_y + y,
+                     GDI_WIDTH, gfx->width,
+                     GDI_HEIGHT, gfx->height,
+                     GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
+                     GDI_STATE, GD_BUTTON_UNPRESSED,
+                     GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
+                     GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
+                     GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
+                     GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
+                     GDI_DECORATION_SIZE, pos->size, pos->size,
+                     GDI_DECORATION_SHIFTING, 1, 1,
+                     GDI_DIRECT_DRAW, FALSE,
+                     GDI_OVERLAY_TOUCH_BUTTON, is_touch_button,
+                     GDI_EVENT_MASK, event_mask,
+                     GDI_CALLBACK_ACTION, HandleToolButtons,
+                     GDI_END);
+
+    if (gi == NULL)
+      Fail("cannot create gadget");
+
+    tool_gadget[id] = gi;
+  }
+}
+
+void FreeToolButtons(void)
+{
+  int i;
+
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
+    FreeGadget(tool_gadget[i]);
+}
+
+static void MapToolButtons(unsigned int req_state)
+{
+  if (req_state & REQ_ASK)
+  {
+    MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_YES]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_NO]);
+  }
+  else if (req_state & REQ_CONFIRM)
+  {
+    MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_TOUCH_CONFIRM]);
+  }
+  else if (req_state & REQ_PLAYER)
+  {
+    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
+    MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
+  }
+}
+
+static void UnmapToolButtons(void)
+{
+  int i;
+
+  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
+    UnmapGadget(tool_gadget[i]);
+}
+
+static void HandleToolButtons(struct GadgetInfo *gi)
+{
+  request_gadget_id = gi->custom_id;
+}
+
+static int getEngineElement_Ext(int element, int game_engine_type, boolean is_drawing_element)
+{
+  int el_empty;
+  int el_player;
+  int el_sand;
+  int el_wall;
+  int el_steelwall;
+  int el_exit_closed;
+
+  if (game_engine_type == -1)
+    game_engine_type = level.game_engine_type;
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+  {
+    el_empty           = EL_EMPTY;
+    el_player          = EL_BDX_PLAYER;
+    el_sand            = EL_BDX_SAND_1;
+    el_wall            = EL_BDX_WALL;
+    el_steelwall       = EL_BDX_STEELWALL;
+    el_exit_closed     = EL_BDX_EXIT_CLOSED;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    el_empty           = EL_EMPTY;
+    el_player          = EL_PLAYER_1;
+    el_sand            = EL_SAND;
+    el_wall            = EL_WALL;
+    el_steelwall       = EL_STEELWALL;
+    el_exit_closed     = EL_EM_EXIT_CLOSED;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    el_empty           = EL_EMPTY;
+    el_player          = EL_SP_MURPHY;
+    el_sand            = EL_SP_BASE;
+    el_wall            = EL_SP_CHIP_SINGLE;
+    el_steelwall       = EL_SP_HARDWARE_GRAY;
+    el_exit_closed     = EL_SP_EXIT_CLOSED;
+  }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
+  {
+    el_empty           = EL_EMPTY;
+    el_player          = EL_MM_MCDUFFIN_DOWN;
+    el_sand            = EL_EMPTY;
+    el_wall            = EL_MM_WOODEN_WALL;
+    el_steelwall       = EL_MM_STEEL_WALL;
+    el_exit_closed     = EL_MM_EXIT_CLOSED;
+
+    if (is_drawing_element)
+    {
+      el_wall          = EL_MM_MIRROR_START;
+      el_sand          = EL_MM_WOODEN_WALL;
+    }
+  }
+  else
+  {
+    el_empty           = EL_EMPTY;
+    el_player          = EL_PLAYER_1;
+    el_sand            = EL_SAND;
+    el_wall            = EL_WALL;
+    el_steelwall       = EL_STEELWALL;
+    el_exit_closed     = EL_EXIT_CLOSED;
+  }
+
+  return (element == EL_EMPTY          ? el_empty :
+         element == EL_PLAYER_1        ? el_player :
+         element == EL_SAND            ? el_sand :
+         element == EL_WALL            ? el_wall :
+         element == EL_STEELWALL       ? el_steelwall :
+         element == EL_EXIT_CLOSED     ? el_exit_closed : EL_EMPTY);
+}
+
+int getEngineElement(int element)
+{
+  return getEngineElement_Ext(element, -1, FALSE);
+}
+
+int getDrawingElement(int element)
+{
+  return getEngineElement_Ext(element, -1, TRUE);
+}
+
+static struct Mapping_BD_to_RND_object
+{
+  int element_bd;
+  boolean is_rnd_to_bd_mapping;                // unique mapping BD <-> RND
+
+  int element_rnd;
+  int action;
+  int direction;
+}
+bd_object_mapping_list[] =
+{
+  // additional RND style elements mapped to BD style elements (must be listed first)
+
+  {
+    O_DIRT,                                    TRUE,
+    EL_SAND,                                   -1, -1
+  },
+  {
+    O_STONE,                                   TRUE,
+    EL_BD_ROCK,                                        -1, -1
+  },
+  {
+    O_BRICK,                                   TRUE,
+    EL_BD_WALL,                                        -1, -1
+  },
+  {
+    O_STEEL,                                   TRUE,
+    EL_STEELWALL,                              -1, -1
+  },
+  {
+    O_DIAMOND,                                 TRUE,
+    EL_BD_DIAMOND,                             -1, -1
+  },
+  {
+    O_INBOX,                                   TRUE,
+    EL_PLAYER_1,                               -1, -1
+  },
+  {
+    O_INBOX,                                   TRUE,
+    EL_PLAYER_2,                               -1, -1
+  },
+  {
+    O_INBOX,                                   TRUE,
+    EL_PLAYER_3,                               -1, -1
+  },
+  {
+    O_INBOX,                                   TRUE,
+    EL_PLAYER_4,                               -1, -1
+  },
+  {
+    O_PRE_OUTBOX,                              TRUE,
+    EL_EXIT_CLOSED,                            -1, -1
+  },
+
+  // BD style elements with their corresponding RND style elements
+
+  {
+    O_SPACE,                                   TRUE,
+    EL_EMPTY,                                  -1, -1
+  },
+  {
+    O_DIRT,                                    TRUE,
+    EL_BDX_SAND_1,                             -1, -1
+  },
+  {
+    O_DIRT_SLOPED_UP_RIGHT,                    TRUE,
+    EL_BDX_SAND_SLOPED_UP_RIGHT,               -1, -1
+  },
+  {
+    O_DIRT_SLOPED_UP_LEFT,                     TRUE,
+    EL_BDX_SAND_SLOPED_UP_LEFT,                        -1, -1
+  },
+  {
+    O_DIRT_SLOPED_DOWN_LEFT,                   TRUE,
+    EL_BDX_SAND_SLOPED_DOWN_LEFT,              -1, -1
+  },
+  {
+    O_DIRT_SLOPED_DOWN_RIGHT,                  TRUE,
+    EL_BDX_SAND_SLOPED_DOWN_RIGHT,             -1, -1
+  },
+  {
+    O_DIRT_BALL,                               TRUE,
+    EL_BDX_SAND_BALL,                          -1, -1
+  },
+  {
+    O_DIRT_BALL_F,                             TRUE,
+    EL_BDX_SAND_BALL_FALLING,                  -1, -1
+  },
+  {
+    O_DIRT_BALL_F,                             FALSE,
+    EL_BDX_SAND_BALL,                          ACTION_FALLING, -1
+  },
+  {
+    O_DIRT_LOOSE,                              TRUE,
+    EL_BDX_SAND_LOOSE,                         -1, -1
+  },
+  {
+    O_DIRT_LOOSE_F,                            TRUE,
+    EL_BDX_SAND_LOOSE_FALLING,                 -1, -1
+  },
+  {
+    O_DIRT_LOOSE_F,                            FALSE,
+    EL_BDX_SAND_LOOSE,                         ACTION_FALLING, -1
+  },
+  {
+    O_DIRT2,                                   TRUE,
+    EL_BDX_SAND_2,                             -1, -1
+  },
+  {
+    O_BRICK,                                   TRUE,
+    EL_BDX_WALL,                               -1, -1
+  },
+  {
+    O_BRICK_SLOPED_UP_RIGHT,                   TRUE,
+    EL_BDX_WALL_SLOPED_UP_RIGHT,               -1, -1
+  },
+  {
+    O_BRICK_SLOPED_UP_LEFT,                    TRUE,
+    EL_BDX_WALL_SLOPED_UP_LEFT,                        -1, -1
+  },
+  {
+    O_BRICK_SLOPED_DOWN_LEFT,                  TRUE,
+    EL_BDX_WALL_SLOPED_DOWN_LEFT,              -1, -1
+  },
+  {
+    O_BRICK_SLOPED_DOWN_RIGHT,                 TRUE,
+    EL_BDX_WALL_SLOPED_DOWN_RIGHT,             -1, -1
+  },
+  {
+    O_BRICK_NON_SLOPED,                                TRUE,
+    EL_BDX_WALL_NON_SLOPED,                    -1, -1
+  },
+  {
+    O_MAGIC_WALL,                              TRUE,
+    EL_BDX_MAGIC_WALL,                         ACTION_ACTIVE, -1
+  },
+  {
+    O_PRE_OUTBOX,                              TRUE,
+    EL_BDX_EXIT_CLOSED,                                -1, -1
+  },
+  {
+    O_OUTBOX,                                  TRUE,
+    EL_BDX_EXIT_OPEN,                          -1, -1
+  },
+  {
+    O_PRE_INVIS_OUTBOX,                                TRUE,
+    EL_BDX_INVISIBLE_EXIT_CLOSED,              -1, -1
+  },
+  {
+    O_INVIS_OUTBOX,                            TRUE,
+    EL_BDX_INVISIBLE_EXIT_OPEN,                        -1, -1
+  },
+  {
+    O_STEEL,                                   TRUE,
+    EL_BDX_STEELWALL,                          -1, -1
+  },
+  {
+    O_STEEL_SLOPED_UP_RIGHT,                   TRUE,
+    EL_BDX_STEELWALL_SLOPED_UP_RIGHT,          -1, -1
+  },
+  {
+    O_STEEL_SLOPED_UP_LEFT,                    TRUE,
+    EL_BDX_STEELWALL_SLOPED_UP_LEFT,           -1, -1
+  },
+  {
+    O_STEEL_SLOPED_DOWN_LEFT,                  TRUE,
+    EL_BDX_STEELWALL_SLOPED_DOWN_LEFT,         -1, -1
+  },
+  {
+    O_STEEL_SLOPED_DOWN_RIGHT,                 TRUE,
+    EL_BDX_STEELWALL_SLOPED_DOWN_RIGHT,                -1, -1
+  },
+  {
+    O_STEEL_EXPLODABLE,                                TRUE,
+    EL_BDX_STEELWALL_EXPLODABLE,               -1, -1
+  },
+  {
+    O_STEEL_EATABLE,                           TRUE,
+    EL_BDX_STEELWALL_DIGGABLE,                 -1, -1
+  },
+  {
+    O_BRICK_EATABLE,                           TRUE,
+    EL_BDX_WALL_DIGGABLE,                      -1, -1
+  },
+  {
+    O_STONE,                                   TRUE,
+    EL_BDX_ROCK,                               -1, -1
+  },
+  {
+    O_STONE_F,                                 TRUE,
+    EL_BDX_ROCK_FALLING,                       -1, -1
+  },
+  {
+    O_STONE_F,                                 FALSE,
+    EL_BDX_ROCK,                               ACTION_FALLING, -1
+  },
+  {
+    O_FLYING_STONE,                            TRUE,
+    EL_BDX_FLYING_ROCK,                                -1, -1
+  },
+  {
+    O_FLYING_STONE_F,                          TRUE,
+    EL_BDX_FLYING_ROCK_FLYING,                 -1, -1
+  },
+  {
+    O_FLYING_STONE_F,                          FALSE,
+    EL_BDX_FLYING_ROCK,                                ACTION_FLYING, -1
+  },
+  {
+    O_MEGA_STONE,                              TRUE,
+    EL_BDX_MEGA_ROCK,                          -1, -1
+  },
+  {
+    O_MEGA_STONE_F,                            TRUE,
+    EL_BDX_MEGA_ROCK_FALLING,                  -1, -1
+  },
+  {
+    O_MEGA_STONE_F,                            FALSE,
+    EL_BDX_MEGA_ROCK,                          ACTION_FALLING, -1
+  },
+  {
+    O_DIAMOND,                                 TRUE,
+    EL_BDX_DIAMOND,                            -1, -1
+  },
+  {
+    O_DIAMOND_F,                               TRUE,
+    EL_BDX_DIAMOND_FALLING,                    -1, -1
+  },
+  {
+    O_DIAMOND_F,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_FALLING, -1
+  },
+  {
+    O_FLYING_DIAMOND,                          TRUE,
+    EL_BDX_FLYING_DIAMOND,                     -1, -1
+  },
+  {
+    O_FLYING_DIAMOND_F,                                TRUE,
+    EL_BDX_FLYING_DIAMOND_FLYING,              -1, -1
+  },
+  {
+    O_FLYING_DIAMOND_F,                                FALSE,
+    EL_BDX_FLYING_DIAMOND,                     ACTION_FLYING, -1
+  },
+  {
+    O_NUT,                                     TRUE,
+    EL_BDX_NUT,                                        -1, -1
+  },
+  {
+    O_NUT_F,                                   TRUE,
+    EL_BDX_NUT_FALLING,                                -1, -1
+  },
+  {
+    O_NUT_F,                                   FALSE,
+    EL_BDX_NUT,                                        ACTION_FALLING, -1
+  },
+  {
+    O_BLADDER_SPENDER,                         TRUE,
+    EL_BDX_BLADDER_SPENDER,                    -1, -1
+  },
+  {
+    O_INBOX,                                   TRUE,
+    EL_BDX_INBOX,                              -1, -1
+  },
+  {
+    O_H_EXPANDING_WALL,                                TRUE,
+    EL_BDX_EXPANDABLE_WALL_HORIZONTAL,         -1, -1
+  },
+  {
+    O_V_EXPANDING_WALL,                                TRUE,
+    EL_BDX_EXPANDABLE_WALL_VERTICAL,           -1, -1
+  },
+  {
+    O_EXPANDING_WALL,                          TRUE,
+    EL_BDX_EXPANDABLE_WALL_ANY,                        -1, -1
+  },
+  {
+    O_H_EXPANDING_STEEL_WALL,                  TRUE,
+    EL_BDX_EXPANDABLE_STEELWALL_HORIZONTAL,    -1, -1
+  },
+  {
+    O_V_EXPANDING_STEEL_WALL,                  TRUE,
+    EL_BDX_EXPANDABLE_STEELWALL_VERTICAL,      -1, -1
+  },
+  {
+    O_EXPANDING_STEEL_WALL,                    TRUE,
+    EL_BDX_EXPANDABLE_STEELWALL_ANY,           -1, -1
+  },
+  {
+    O_EXPANDING_WALL_SWITCH,                   TRUE,
+    EL_BDX_EXPANDABLE_WALL_SWITCH,             -1, -1
+  },
+  {
+    O_CREATURE_SWITCH,                         TRUE,
+    EL_BDX_CREATURE_SWITCH,                    -1, -1
+  },
+  {
+    O_BITER_SWITCH,                            TRUE,
+    EL_BDX_BITER_SWITCH_1,                     -1, -1
+  },
+  {
+    O_REPLICATOR_SWITCH,                       TRUE,
+    EL_BDX_REPLICATOR_SWITCH,                  -1, -1
+  },
+  {
+    O_CONVEYOR_SWITCH,                         TRUE,
+    EL_BDX_CONVEYOR_SWITCH,                    -1, -1
+  },
+  {
+    O_CONVEYOR_DIR_SWITCH,                     TRUE,
+    EL_BDX_CONVEYOR_DIR_SWITCH,                        -1, -1
+  },
+  {
+    O_ACID,                                    TRUE,
+    EL_BDX_ACID,                               -1, -1
+  },
+  {
+    O_FALLING_WALL,                            TRUE,
+    EL_BDX_FALLING_WALL,                       -1, -1
+  },
+  {
+    O_FALLING_WALL_F,                          TRUE,
+    EL_BDX_FALLING_WALL_FALLING,               -1, -1
+  },
+  {
+    O_FALLING_WALL_F,                          FALSE,
+    EL_BDX_FALLING_WALL,                       ACTION_FALLING, -1
+  },
+  {
+    O_BOX,                                     TRUE,
+    EL_BDX_BOX,                                        -1, -1
+  },
+  {
+    O_TIME_PENALTY,                            TRUE,
+    EL_BDX_TIME_PENALTY,                       -1, -1
+  },
+  {
+    O_GRAVESTONE,                              TRUE,
+    EL_BDX_GRAVESTONE,                         -1, -1
+  },
+  {
+    O_STONE_GLUED,                             TRUE,
+    EL_BDX_ROCK_GLUED,                         -1, -1
+  },
+  {
+    O_DIAMOND_GLUED,                           TRUE,
+    EL_BDX_DIAMOND_GLUED,                      -1, -1
+  },
+  {
+    O_DIAMOND_KEY,                             TRUE,
+    EL_BDX_DIAMOND_KEY,                                -1, -1
+  },
+  {
+    O_TRAPPED_DIAMOND,                         TRUE,
+    EL_BDX_TRAPPED_DIAMOND,                    -1, -1
+  },
+  {
+    O_CLOCK,                                   TRUE,
+    EL_BDX_CLOCK,                              -1, -1
+  },
+  {
+    O_DIRT_GLUED,                              TRUE,
+    EL_BDX_SAND_GLUED,                         -1, -1
+  },
+  {
+    O_KEY_1,                                   TRUE,
+    EL_BDX_KEY_1,                              -1, -1
+  },
+  {
+    O_KEY_2,                                   TRUE,
+    EL_BDX_KEY_2,                              -1, -1
+  },
+  {
+    O_KEY_3,                                   TRUE,
+    EL_BDX_KEY_3,                              -1, -1
+  },
+  {
+    O_DOOR_1,                                  TRUE,
+    EL_BDX_GATE_1,                             -1, -1
+  },
+  {
+    O_DOOR_2,                                  TRUE,
+    EL_BDX_GATE_2,                             -1, -1
+  },
+  {
+    O_DOOR_3,                                  TRUE,
+    EL_BDX_GATE_3,                             -1, -1
+  },
+  {
+    O_POT,                                     TRUE,
+    EL_BDX_POT,                                        -1, -1
+  },
+  {
+    O_GRAVITY_SWITCH,                          TRUE,
+    EL_BDX_GRAVITY_SWITCH,                     -1, -1
+  },
+  {
+    O_PNEUMATIC_HAMMER,                                TRUE,
+    EL_BDX_PNEUMATIC_HAMMER,                   -1, -1
+  },
+  {
+    O_TELEPORTER,                              TRUE,
+    EL_BDX_TELEPORTER,                         -1, -1
+  },
+  {
+    O_SKELETON,                                        TRUE,
+    EL_BDX_SKELETON,                           -1, -1
+  },
+  {
+    O_WATER,                                   TRUE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_1,                                 TRUE,
+    EL_BDX_WATER_1,                            -1, -1
+  },
+  {
+    O_WATER_1,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_2,                                 TRUE,
+    EL_BDX_WATER_2,                            -1, -1
+  },
+  {
+    O_WATER_2,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_3,                                 TRUE,
+    EL_BDX_WATER_3,                            -1, -1
+  },
+  {
+    O_WATER_3,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_4,                                 TRUE,
+    EL_BDX_WATER_4,                            -1, -1
+  },
+  {
+    O_WATER_4,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_5,                                 TRUE,
+    EL_BDX_WATER_5,                            -1, -1
+  },
+  {
+    O_WATER_5,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_6,                                 TRUE,
+    EL_BDX_WATER_6,                            -1, -1
+  },
+  {
+    O_WATER_6,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_7,                                 TRUE,
+    EL_BDX_WATER_7,                            -1, -1
+  },
+  {
+    O_WATER_7,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_8,                                 TRUE,
+    EL_BDX_WATER_8,                            -1, -1
+  },
+  {
+    O_WATER_8,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_9,                                 TRUE,
+    EL_BDX_WATER_9,                            -1, -1
+  },
+  {
+    O_WATER_9,                                 FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_10,                                        TRUE,
+    EL_BDX_WATER_10,                           -1, -1
+  },
+  {
+    O_WATER_10,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_11,                                        TRUE,
+    EL_BDX_WATER_11,                           -1, -1
+  },
+  {
+    O_WATER_11,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_12,                                        TRUE,
+    EL_BDX_WATER_12,                           -1, -1
+  },
+  {
+    O_WATER_12,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_13,                                        TRUE,
+    EL_BDX_WATER_13,                           -1, -1
+  },
+  {
+    O_WATER_13,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_14,                                        TRUE,
+    EL_BDX_WATER_14,                           -1, -1
+  },
+  {
+    O_WATER_14,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_15,                                        TRUE,
+    EL_BDX_WATER_15,                           -1, -1
+  },
+  {
+    O_WATER_15,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_WATER_16,                                        TRUE,
+    EL_BDX_WATER_16,                           -1, -1
+  },
+  {
+    O_WATER_16,                                        FALSE,
+    EL_BDX_WATER,                              -1, -1
+  },
+  {
+    O_COW_1,                                   TRUE,
+    EL_BDX_COW_LEFT,                           -1, -1
+  },
+  {
+    O_COW_2,                                   TRUE,
+    EL_BDX_COW_UP,                             -1, -1
+  },
+  {
+    O_COW_3,                                   TRUE,
+    EL_BDX_COW_RIGHT,                          -1, -1
+  },
+  {
+    O_COW_4,                                   TRUE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_1,                          TRUE,
+    EL_BDX_COW_ENCLOSED_1,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_1,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_2,                          TRUE,
+    EL_BDX_COW_ENCLOSED_2,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_2,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_3,                          TRUE,
+    EL_BDX_COW_ENCLOSED_3,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_3,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_4,                          TRUE,
+    EL_BDX_COW_ENCLOSED_4,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_4,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_5,                          TRUE,
+    EL_BDX_COW_ENCLOSED_5,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_5,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_6,                          TRUE,
+    EL_BDX_COW_ENCLOSED_6,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_6,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_COW_ENCLOSED_7,                          TRUE,
+    EL_BDX_COW_ENCLOSED_7,                     -1, -1
+  },
+  {
+    O_COW_ENCLOSED_7,                          FALSE,
+    EL_BDX_COW_DOWN,                           -1, -1
+  },
+  {
+    O_WALLED_DIAMOND,                          TRUE,
+    EL_BDX_WALL_DIAMOND,                       -1, -1
+  },
+  {
+    O_WALLED_KEY_1,                            TRUE,
+    EL_BDX_WALL_KEY_1,                         -1, -1
+  },
+  {
+    O_WALLED_KEY_2,                            TRUE,
+    EL_BDX_WALL_KEY_2,                         -1, -1
+  },
+  {
+    O_WALLED_KEY_3,                            TRUE,
+    EL_BDX_WALL_KEY_3,                         -1, -1
+  },
+  {
+    O_AMOEBA,                                  TRUE,
+    EL_BDX_AMOEBA_1,                           -1, -1
+  },
+  {
+    O_AMOEBA_2,                                        TRUE,
+    EL_BDX_AMOEBA_2,                           -1, -1
+  },
+  {
+    O_REPLICATOR,                              TRUE,
+    EL_BDX_REPLICATOR,                         -1, -1
+  },
+  {
+    O_CONVEYOR_LEFT,                           TRUE,
+    EL_BDX_CONVEYOR_LEFT,                      -1, -1
+  },
+  {
+    O_CONVEYOR_RIGHT,                          TRUE,
+    EL_BDX_CONVEYOR_RIGHT,                     -1, -1
+  },
+  {
+    O_LAVA,                                    TRUE,
+    EL_BDX_LAVA,                               -1, -1
+  },
+  {
+    O_SWEET,                                   TRUE,
+    EL_BDX_SWEET,                              -1, -1
+  },
+  {
+    O_VOODOO,                                  TRUE,
+    EL_BDX_VOODOO_DOLL,                                -1, -1
+  },
+  {
+    O_SLIME,                                   TRUE,
+    EL_BDX_SLIME,                              -1, -1
+  },
+  {
+    O_BLADDER,                                 TRUE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_1,                               TRUE,
+    EL_BDX_BLADDER_1,                          -1, -1
+  },
+  {
+    O_BLADDER_1,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_2,                               TRUE,
+    EL_BDX_BLADDER_2,                          -1, -1
+  },
+  {
+    O_BLADDER_2,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_3,                               TRUE,
+    EL_BDX_BLADDER_3,                          -1, -1
+  },
+  {
+    O_BLADDER_3,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_4,                               TRUE,
+    EL_BDX_BLADDER_4,                          -1, -1
+  },
+  {
+    O_BLADDER_4,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_5,                               TRUE,
+    EL_BDX_BLADDER_5,                          -1, -1
+  },
+  {
+    O_BLADDER_5,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_6,                               TRUE,
+    EL_BDX_BLADDER_6,                          -1, -1
+  },
+  {
+    O_BLADDER_6,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_7,                               TRUE,
+    EL_BDX_BLADDER_7,                          -1, -1
+  },
+  {
+    O_BLADDER_7,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_BLADDER_8,                               TRUE,
+    EL_BDX_BLADDER_8,                          -1, -1
+  },
+  {
+    O_BLADDER_8,                               FALSE,
+    EL_BDX_BLADDER,                            -1, -1
+  },
+  {
+    O_WAITING_STONE,                           TRUE,
+    EL_BDX_WAITING_ROCK,                       -1, -1
+  },
+  {
+    O_CHASING_STONE,                           TRUE,
+    EL_BDX_CHASING_ROCK,                       -1, -1
+  },
+  {
+    O_GHOST,                                   TRUE,
+    EL_BDX_GHOST,                              -1, -1
+  },
+  {
+    O_FIREFLY_1,                               TRUE,
+    EL_BDX_FIREFLY_1_LEFT,                     -1, -1
+  },
+  {
+    O_FIREFLY_2,                               TRUE,
+    EL_BDX_FIREFLY_1_UP,                       -1, -1
+  },
+  {
+    O_FIREFLY_3,                               TRUE,
+    EL_BDX_FIREFLY_1_RIGHT,                    -1, -1
+  },
+  {
+    O_FIREFLY_4,                               TRUE,
+    EL_BDX_FIREFLY_1_DOWN,                     -1, -1
+  },
+  {
+    O_ALT_FIREFLY_1,                           TRUE,
+    EL_BDX_FIREFLY_2_LEFT,                     -1, -1
+  },
+  {
+    O_ALT_FIREFLY_2,                           TRUE,
+    EL_BDX_FIREFLY_2_UP,                       -1, -1
+  },
+  {
+    O_ALT_FIREFLY_3,                           TRUE,
+    EL_BDX_FIREFLY_2_RIGHT,                    -1, -1
+  },
+  {
+    O_ALT_FIREFLY_4,                           TRUE,
+    EL_BDX_FIREFLY_2_DOWN,                     -1, -1
+  },
+  {
+    O_BUTTER_1,                                        TRUE,
+    EL_BDX_BUTTERFLY_1_LEFT,                   -1, -1
+  },
+  {
+    O_BUTTER_2,                                        TRUE,
+    EL_BDX_BUTTERFLY_1_UP,                     -1, -1
+  },
+  {
+    O_BUTTER_3,                                        TRUE,
+    EL_BDX_BUTTERFLY_1_RIGHT,                  -1, -1
+  },
+  {
+    O_BUTTER_4,                                        TRUE,
+    EL_BDX_BUTTERFLY_1_DOWN,                   -1, -1
+  },
+  {
+    O_ALT_BUTTER_1,                            TRUE,
+    EL_BDX_BUTTERFLY_2_LEFT,                   -1, -1
+  },
+  {
+    O_ALT_BUTTER_2,                            TRUE,
+    EL_BDX_BUTTERFLY_2_UP,                     -1, -1
+  },
+  {
+    O_ALT_BUTTER_3,                            TRUE,
+    EL_BDX_BUTTERFLY_2_RIGHT,                  -1, -1
+  },
+  {
+    O_ALT_BUTTER_4,                            TRUE,
+    EL_BDX_BUTTERFLY_2_DOWN,                   -1, -1
+  },
+  {
+    O_STONEFLY_1,                              TRUE,
+    EL_BDX_STONEFLY_LEFT,                      -1, -1
+  },
+  {
+    O_STONEFLY_2,                              TRUE,
+    EL_BDX_STONEFLY_UP,                                -1, -1
+  },
+  {
+    O_STONEFLY_3,                              TRUE,
+    EL_BDX_STONEFLY_RIGHT,                     -1, -1
+  },
+  {
+    O_STONEFLY_4,                              TRUE,
+    EL_BDX_STONEFLY_DOWN,                      -1, -1
+  },
+  {
+    O_BITER_1,                                 TRUE,
+    EL_BDX_BITER_UP,                           -1, -1
+  },
+  {
+    O_BITER_2,                                 TRUE,
+    EL_BDX_BITER_RIGHT,                                -1, -1
+  },
+  {
+    O_BITER_3,                                 TRUE,
+    EL_BDX_BITER_DOWN,                         -1, -1
+  },
+  {
+    O_BITER_4,                                 TRUE,
+    EL_BDX_BITER_LEFT,                         -1, -1
+  },
+  {
+    O_DRAGONFLY_1,                             TRUE,
+    EL_BDX_DRAGONFLY_LEFT,                     -1, -1
+  },
+  {
+    O_DRAGONFLY_2,                             TRUE,
+    EL_BDX_DRAGONFLY_UP,                       -1, -1
+  },
+  {
+    O_DRAGONFLY_3,                             TRUE,
+    EL_BDX_DRAGONFLY_RIGHT,                    -1, -1
+  },
+  {
+    O_DRAGONFLY_4,                             TRUE,
+    EL_BDX_DRAGONFLY_DOWN,                     -1, -1
+  },
+  {
+    O_PRE_PL_1,                                        TRUE,
+    EL_BDX_PLAYER_GROWING_1,                   -1, -1
+  },
+  {
+    O_PRE_PL_1,                                        FALSE,
+    EL_BDX_PLAYER,                             ACTION_GROWING, -1
+  },
+  {
+    O_PRE_PL_2,                                        TRUE,
+    EL_BDX_PLAYER_GROWING_2,                   -1, -1
+  },
+  {
+    O_PRE_PL_2,                                        FALSE,
+    EL_BDX_PLAYER,                             ACTION_GROWING, -1
+  },
+  {
+    O_PRE_PL_3,                                        TRUE,
+    EL_BDX_PLAYER_GROWING_3,                   -1, -1
+  },
+  {
+    O_PRE_PL_3,                                        FALSE,
+    EL_BDX_PLAYER,                             ACTION_GROWING, -1
+  },
+  {
+    O_PLAYER,                                  TRUE,
+    EL_BDX_PLAYER,                             -1, -1
+  },
+  {
+    O_PLAYER_BOMB,                             TRUE,
+    EL_BDX_PLAYER_WITH_BOMB,                   -1, -1
+  },
+  {
+    O_PLAYER_ROCKET_LAUNCHER,                  TRUE,
+    EL_BDX_PLAYER_WITH_ROCKET_LAUNCHER,                -1, -1
+  },
+  {
+    O_PLAYER_GLUED,                            TRUE,
+    EL_BDX_PLAYER_GLUED,                       -1, -1
+  },
+  {
+    O_PLAYER_STIRRING,                         TRUE,
+    EL_BDX_PLAYER_STIRRING,                    -1, -1
+  },
+  {
+    O_ROCKET_LAUNCHER,                         TRUE,
+    EL_BDX_ROCKET_LAUNCHER,                    -1, -1
+  },
+  {
+    O_ROCKET_1,                                        TRUE,
+    EL_BDX_ROCKET_RIGHT,                       -1, -1
+  },
+  {
+    O_ROCKET_2,                                        TRUE,
+    EL_BDX_ROCKET_UP,                          -1, -1
+  },
+  {
+    O_ROCKET_3,                                        TRUE,
+    EL_BDX_ROCKET_LEFT,                                -1, -1
+  },
+  {
+    O_ROCKET_4,                                        TRUE,
+    EL_BDX_ROCKET_DOWN,                                -1, -1
+  },
+  {
+    O_BOMB,                                    TRUE,
+    EL_BDX_BOMB,                               -1, -1
+  },
+  {
+    O_BOMB_TICK_1,                             TRUE,
+    EL_BDX_BOMB_TICKING_1,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_1,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_2,                             TRUE,
+    EL_BDX_BOMB_TICKING_2,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_2,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_3,                             TRUE,
+    EL_BDX_BOMB_TICKING_3,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_3,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_4,                             TRUE,
+    EL_BDX_BOMB_TICKING_4,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_4,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_5,                             TRUE,
+    EL_BDX_BOMB_TICKING_5,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_5,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_6,                             TRUE,
+    EL_BDX_BOMB_TICKING_6,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_6,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_BOMB_TICK_7,                             TRUE,
+    EL_BDX_BOMB_TICKING_7,                     -1, -1
+  },
+  {
+    O_BOMB_TICK_7,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_ACTIVE, -1
+  },
+  {
+    O_NITRO_PACK,                              TRUE,
+    EL_BDX_NITRO_PACK,                         -1, -1
+  },
+  {
+    O_NITRO_PACK_F,                            TRUE,
+    EL_BDX_NITRO_PACK_FALLING,                 -1, -1
+  },
+  {
+    O_NITRO_PACK_F,                            FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_FALLING, -1
+  },
+  {
+    O_PRE_CLOCK_1,                             TRUE,
+    EL_BDX_CLOCK_GROWING_1,                    -1, -1
+  },
+  {
+    O_PRE_CLOCK_1,                             FALSE,
+    EL_BDX_CLOCK,                              ACTION_GROWING, -1
+  },
+  {
+    O_PRE_CLOCK_2,                             TRUE,
+    EL_BDX_CLOCK_GROWING_2,                    -1, -1
+  },
+  {
+    O_PRE_CLOCK_2,                             FALSE,
+    EL_BDX_CLOCK,                              ACTION_GROWING, -1
+  },
+  {
+    O_PRE_CLOCK_3,                             TRUE,
+    EL_BDX_CLOCK_GROWING_3,                    -1, -1
+  },
+  {
+    O_PRE_CLOCK_3,                             FALSE,
+    EL_BDX_CLOCK,                              ACTION_GROWING, -1
+  },
+  {
+    O_PRE_CLOCK_4,                             TRUE,
+    EL_BDX_CLOCK_GROWING_4,                    -1, -1
+  },
+  {
+    O_PRE_CLOCK_4,                             FALSE,
+    EL_BDX_CLOCK,                              ACTION_GROWING, -1
+  },
+  {
+    O_PRE_DIA_1,                               TRUE,
+    EL_BDX_DIAMOND_GROWING_1,                  -1, -1
+  },
+  {
+    O_PRE_DIA_1,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_GROWING, -1
+  },
+  {
+    O_PRE_DIA_2,                               TRUE,
+    EL_BDX_DIAMOND_GROWING_2,                  -1, -1
+  },
+  {
+    O_PRE_DIA_2,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_GROWING, -1
+  },
+  {
+    O_PRE_DIA_3,                               TRUE,
+    EL_BDX_DIAMOND_GROWING_3,                  -1, -1
+  },
+  {
+    O_PRE_DIA_3,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_GROWING, -1
+  },
+  {
+    O_PRE_DIA_4,                               TRUE,
+    EL_BDX_DIAMOND_GROWING_4,                  -1, -1
+  },
+  {
+    O_PRE_DIA_4,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_GROWING, -1
+  },
+  {
+    O_PRE_DIA_5,                               TRUE,
+    EL_BDX_DIAMOND_GROWING_5,                  -1, -1
+  },
+  {
+    O_PRE_DIA_5,                               FALSE,
+    EL_BDX_DIAMOND,                            ACTION_GROWING, -1
+  },
+  {
+    O_EXPLODE_1,                               TRUE,
+    EL_BDX_EXPLODING_1,                                -1, -1
+  },
+  {
+    O_EXPLODE_1,                               FALSE,
+    EL_BDX_DEFAULT,                            ACTION_EXPLODING, -1
+  },
+  {
+    O_EXPLODE_2,                               TRUE,
+    EL_BDX_EXPLODING_2,                                -1, -1
+  },
+  {
+    O_EXPLODE_2,                               FALSE,
+    EL_BDX_DEFAULT,                            ACTION_EXPLODING, -1
+  },
+  {
+    O_EXPLODE_3,                               TRUE,
+    EL_BDX_EXPLODING_3,                                -1, -1
+  },
+  {
+    O_EXPLODE_3,                               FALSE,
+    EL_BDX_DEFAULT,                            ACTION_EXPLODING, -1
+  },
+  {
+    O_EXPLODE_4,                               TRUE,
+    EL_BDX_EXPLODING_4,                                -1, -1
+  },
+  {
+    O_EXPLODE_4,                               FALSE,
+    EL_BDX_DEFAULT,                            ACTION_EXPLODING, -1
+  },
+  {
+    O_EXPLODE_5,                               TRUE,
+    EL_BDX_EXPLODING_5,                                -1, -1
+  },
+  {
+    O_EXPLODE_5,                               FALSE,
+    EL_BDX_DEFAULT,                            ACTION_EXPLODING, -1
+  },
+  {
+    O_PRE_STONE_1,                             TRUE,
+    EL_BDX_ROCK_GROWING_1,                     -1, -1
+  },
+  {
+    O_PRE_STONE_1,                             FALSE,
+    EL_BDX_ROCK,                               ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STONE_2,                             TRUE,
+    EL_BDX_ROCK_GROWING_2,                     -1, -1
+  },
+  {
+    O_PRE_STONE_2,                             FALSE,
+    EL_BDX_ROCK,                               ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STONE_3,                             TRUE,
+    EL_BDX_ROCK_GROWING_3,                     -1, -1
+  },
+  {
+    O_PRE_STONE_3,                             FALSE,
+    EL_BDX_ROCK,                               ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STONE_4,                             TRUE,
+    EL_BDX_ROCK_GROWING_4,                     -1, -1
+  },
+  {
+    O_PRE_STONE_4,                             FALSE,
+    EL_BDX_ROCK,                               ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STEEL_1,                             TRUE,
+    EL_BDX_STEELWALL_GROWING_1,                        -1, -1
+  },
+  {
+    O_PRE_STEEL_1,                             FALSE,
+    EL_BDX_STEELWALL,                          ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STEEL_2,                             TRUE,
+    EL_BDX_STEELWALL_GROWING_2,                        -1, -1
+  },
+  {
+    O_PRE_STEEL_2,                             FALSE,
+    EL_BDX_STEELWALL,                          ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STEEL_3,                             TRUE,
+    EL_BDX_STEELWALL_GROWING_3,                        -1, -1
+  },
+  {
+    O_PRE_STEEL_3,                             FALSE,
+    EL_BDX_STEELWALL,                          ACTION_GROWING, -1
+  },
+  {
+    O_PRE_STEEL_4,                             TRUE,
+    EL_BDX_STEELWALL_GROWING_4,                        -1, -1
+  },
+  {
+    O_PRE_STEEL_4,                             FALSE,
+    EL_BDX_STEELWALL,                          ACTION_GROWING, -1
+  },
+  {
+    O_GHOST_EXPL_1,                            TRUE,
+    EL_BDX_GHOST_EXPLODING_1,                  -1, -1
+  },
+  {
+    O_GHOST_EXPL_1,                            FALSE,
+    EL_BDX_GHOST,                              ACTION_EXPLODING, -1
+  },
+  {
+    O_GHOST_EXPL_2,                            TRUE,
+    EL_BDX_GHOST_EXPLODING_2,                  -1, -1
+  },
+  {
+    O_GHOST_EXPL_2,                            FALSE,
+    EL_BDX_GHOST,                              ACTION_EXPLODING, -1
+  },
+  {
+    O_GHOST_EXPL_3,                            TRUE,
+    EL_BDX_GHOST_EXPLODING_3,                  -1, -1
+  },
+  {
+    O_GHOST_EXPL_3,                            FALSE,
+    EL_BDX_GHOST,                              ACTION_EXPLODING, -1
+  },
+  {
+    O_GHOST_EXPL_4,                            TRUE,
+    EL_BDX_GHOST_EXPLODING_4,                  -1, -1
+  },
+  {
+    O_GHOST_EXPL_4,                            FALSE,
+    EL_BDX_GHOST,                              ACTION_EXPLODING, -1
+  },
+  {
+    O_BOMB_EXPL_1,                             TRUE,
+    EL_BDX_BOMB_EXPLODING_1,                   -1, -1
+  },
+  {
+    O_BOMB_EXPL_1,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_EXPLODING, -1
+  },
+  {
+    O_BOMB_EXPL_2,                             TRUE,
+    EL_BDX_BOMB_EXPLODING_2,                   -1, -1
+  },
+  {
+    O_BOMB_EXPL_2,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_EXPLODING, -1
+  },
+  {
+    O_BOMB_EXPL_3,                             TRUE,
+    EL_BDX_BOMB_EXPLODING_3,                   -1, -1
+  },
+  {
+    O_BOMB_EXPL_3,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_EXPLODING, -1
+  },
+  {
+    O_BOMB_EXPL_4,                             TRUE,
+    EL_BDX_BOMB_EXPLODING_4,                   -1, -1
+  },
+  {
+    O_BOMB_EXPL_4,                             FALSE,
+    EL_BDX_BOMB,                               ACTION_EXPLODING, -1
+  },
+  {
+    O_NITRO_EXPL_1,                            TRUE,
+    EL_BDX_NITRO_PACK_EXPLODING_1,             -1, -1
+  },
+  {
+    O_NITRO_EXPL_1,                            FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_EXPLODING, -1
+  },
+  {
+    O_NITRO_EXPL_2,                            TRUE,
+    EL_BDX_NITRO_PACK_EXPLODING_2,             -1, -1
+  },
+  {
+    O_NITRO_EXPL_2,                            FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_EXPLODING, -1
+  },
+  {
+    O_NITRO_EXPL_3,                            TRUE,
+    EL_BDX_NITRO_PACK_EXPLODING_3,             -1, -1
+  },
+  {
+    O_NITRO_EXPL_3,                            FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_EXPLODING, -1
+  },
+  {
+    O_NITRO_EXPL_4,                            TRUE,
+    EL_BDX_NITRO_PACK_EXPLODING_4,             -1, -1
+  },
+  {
+    O_NITRO_EXPL_4,                            FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_EXPLODING, -1
+  },
+  {
+    O_NITRO_PACK_EXPLODE,                      TRUE,
+    EL_BDX_NITRO_PACK_EXPLODING,               -1, -1
+  },
+  {
+    O_NITRO_PACK_EXPLODE,                      FALSE,
+    EL_BDX_NITRO_PACK,                         ACTION_EXPLODING, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_1,                         TRUE,
+    EL_BDX_AMOEBA_2_EXPLODING_1,               -1, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_1,                         FALSE,
+    EL_BDX_AMOEBA_2,                           ACTION_EXPLODING, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_2,                         TRUE,
+    EL_BDX_AMOEBA_2_EXPLODING_2,               -1, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_2,                         FALSE,
+    EL_BDX_AMOEBA_2,                           ACTION_EXPLODING, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_3,                         TRUE,
+    EL_BDX_AMOEBA_2_EXPLODING_3,               -1, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_3,                         FALSE,
+    EL_BDX_AMOEBA_2,                           ACTION_EXPLODING, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_4,                         TRUE,
+    EL_BDX_AMOEBA_2_EXPLODING_4,               -1, -1
+  },
+  {
+    O_AMOEBA_2_EXPL_4,                         FALSE,
+    EL_BDX_AMOEBA_2,                           ACTION_EXPLODING, -1
+  },
+  {
+    O_NUT_EXPL_1,                              TRUE,
+    EL_BDX_NUT_BREAKING_1,                     -1, -1
+  },
+  {
+    O_NUT_EXPL_1,                              FALSE,
+    EL_BDX_NUT,                                        ACTION_BREAKING, -1
+  },
+  {
+    O_NUT_EXPL_2,                              TRUE,
+    EL_BDX_NUT_BREAKING_2,                     -1, -1
+  },
+  {
+    O_NUT_EXPL_2,                              FALSE,
+    EL_BDX_NUT,                                        ACTION_BREAKING, -1
+  },
+  {
+    O_NUT_EXPL_3,                              TRUE,
+    EL_BDX_NUT_BREAKING_3,                     -1, -1
+  },
+  {
+    O_NUT_EXPL_3,                              FALSE,
+    EL_BDX_NUT,                                        ACTION_BREAKING, -1
+  },
+  {
+    O_NUT_EXPL_4,                              TRUE,
+    EL_BDX_NUT_BREAKING_4,                     -1, -1
+  },
+  {
+    O_NUT_EXPL_4,                              FALSE,
+    EL_BDX_NUT,                                        ACTION_BREAKING, -1
+  },
+  {
+    O_PLAYER_PNEUMATIC_LEFT,                   FALSE,
+    EL_BDX_PLAYER,                             ACTION_HITTING, MV_BIT_LEFT
+  },
+  {
+    O_PLAYER_PNEUMATIC_RIGHT,                  FALSE,
+    EL_BDX_PLAYER,                             ACTION_HITTING, MV_BIT_RIGHT
+  },
+  {
+    O_PNEUMATIC_ACTIVE_LEFT,                   FALSE,
+    EL_BDX_PNEUMATIC_HAMMER,                   ACTION_HITTING, MV_BIT_LEFT
+  },
+  {
+    O_PNEUMATIC_ACTIVE_RIGHT,                  FALSE,
+    EL_BDX_PNEUMATIC_HAMMER,                   ACTION_HITTING, MV_BIT_RIGHT
+  },
+
+  // helper (runtime) elements
+
+  {
+    O_FAKE_BONUS,                              FALSE,
+    EL_BDX_FAKE_BONUS,                         -1, -1
+  },
+  {
+    O_INBOX_CLOSED,                            FALSE,
+    EL_BDX_INBOX,                              -1, -1
+  },
+  {
+    O_INBOX_OPEN,                              FALSE,
+    EL_BDX_INBOX,                              ACTION_OPENING, -1
+  },
+  {
+    O_OUTBOX_CLOSED,                           FALSE,
+    EL_BDX_EXIT_CLOSED,                                -1, -1
+  },
+  {
+    O_OUTBOX_OPEN,                             FALSE,
+    EL_BDX_EXIT_OPEN,                          -1, -1
+  },
+  {
+    O_COVERED,                                 FALSE,
+    EL_BDX_COVERED,                            -1, -1
+  },
+  {
+    O_PLAYER_LEFT,                             FALSE,
+    EL_BDX_PLAYER,                             ACTION_MOVING, MV_BIT_LEFT
+  },
+  {
+    O_PLAYER_RIGHT,                            FALSE,
+    EL_BDX_PLAYER,                             ACTION_MOVING, MV_BIT_RIGHT
+  },
+  {
+    O_PLAYER_UP,                               FALSE,
+    EL_BDX_PLAYER,                             ACTION_MOVING, MV_BIT_UP
+  },
+  {
+    O_PLAYER_DOWN,                             FALSE,
+    EL_BDX_PLAYER,                             ACTION_MOVING, MV_BIT_DOWN
+  },
+  {
+    O_PLAYER_BLINK,                            FALSE,
+    EL_BDX_PLAYER,                             ACTION_BORING_1, -1
+  },
+  {
+    O_PLAYER_TAP,                              FALSE,
+    EL_BDX_PLAYER,                             ACTION_BORING_2, -1
+  },
+  {
+    O_PLAYER_TAP_BLINK,                                FALSE,
+    EL_BDX_PLAYER,                             ACTION_BORING_3, -1
+  },
+  {
+    O_PLAYER_PUSH_LEFT,                                FALSE,
+    EL_BDX_PLAYER,                             ACTION_PUSHING, MV_BIT_LEFT
+  },
+  {
+    O_PLAYER_PUSH_RIGHT,                       FALSE,
+    EL_BDX_PLAYER,                             ACTION_PUSHING, MV_BIT_RIGHT
+  },
+  {
+    O_CREATURE_SWITCH_ON,                      FALSE,
+    EL_BDX_CREATURE_SWITCH_ACTIVE,             -1, -1
+  },
+  {
+    O_EXPANDING_WALL_SWITCH_HORIZ,             FALSE,
+    EL_BDX_EXPANDABLE_WALL_SWITCH,             -1, -1
+  },
+  {
+    O_EXPANDING_WALL_SWITCH_VERT,              FALSE,
+    EL_BDX_EXPANDABLE_WALL_SWITCH_ACTIVE,      -1, -1
+  },
+  {
+    O_GRAVITY_SWITCH_ACTIVE,                   FALSE,
+    EL_BDX_GRAVITY_SWITCH_ACTIVE,              -1, -1
+  },
+  {
+    O_REPLICATOR_SWITCH_OFF,                   FALSE,
+    EL_BDX_REPLICATOR_SWITCH,                  -1, -1
+  },
+  {
+    O_REPLICATOR_SWITCH_ON,                    FALSE,
+    EL_BDX_REPLICATOR_SWITCH_ACTIVE,           -1, -1
+  },
+  {
+    O_CONVEYOR_DIR_NORMAL,                     FALSE,
+    EL_BDX_CONVEYOR_DIR_SWITCH,                        -1, -1
+  },
+  {
+    O_CONVEYOR_DIR_CHANGED,                    FALSE,
+    EL_BDX_CONVEYOR_DIR_SWITCH_ACTIVE,         -1, -1
+  },
+  {
+    O_CONVEYOR_SWITCH_OFF,                     FALSE,
+    EL_BDX_CONVEYOR_SWITCH,                    -1, -1
+  },
+  {
+    O_CONVEYOR_SWITCH_ON,                      FALSE,
+    EL_BDX_CONVEYOR_SWITCH_ACTIVE,             -1, -1
+  },
+  {
+    O_MAGIC_WALL_ACTIVE,                       FALSE,
+    EL_BDX_MAGIC_WALL_ACTIVE,          -1, -1
+  },
+  {
+    O_REPLICATOR_ACTIVE,                       FALSE,
+    EL_BDX_REPLICATOR_ACTIVE,                  -1, -1
+  },
+  {
+    O_CONVEYOR_LEFT_ACTIVE,                    FALSE,
+    EL_BDX_CONVEYOR_LEFT_ACTIVE,               -1, -1
+  },
+  {
+    O_CONVEYOR_RIGHT_ACTIVE,                   FALSE,
+    EL_BDX_CONVEYOR_RIGHT_ACTIVE,              -1, -1
+  },
+  {
+    O_BITER_SWITCH_1,                          FALSE,
+    EL_BDX_BITER_SWITCH_1,                     -1, -1
+  },
+  {
+    O_BITER_SWITCH_2,                          FALSE,
+    EL_BDX_BITER_SWITCH_2,                     -1, -1
+  },
+  {
+    O_BITER_SWITCH_3,                          FALSE,
+    EL_BDX_BITER_SWITCH_3,                     -1, -1
+  },
+  {
+    O_BITER_SWITCH_4,                          FALSE,
+    EL_BDX_BITER_SWITCH_4,                     -1, -1
+  },
+
+  {
+    -1,                                                FALSE,
+    -1,                                                -1, -1
+  }
+};
+
+int map_element_RND_to_BD_cave(int element_rnd)
+{
+  static unsigned short mapping_RND_to_BD[NUM_FILE_ELEMENTS];
+  static boolean mapping_initialized = FALSE;
+
+  if (!mapping_initialized)
+  {
+    int i;
+
+    // return "O_UNKNOWN" for all undefined elements in mapping array
+    for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+      mapping_RND_to_BD[i] = O_UNKNOWN;
+
+    for (i = 0; bd_object_mapping_list[i].element_bd != -1; i++)
+      if (bd_object_mapping_list[i].is_rnd_to_bd_mapping)
+       mapping_RND_to_BD[bd_object_mapping_list[i].element_rnd] =
+         bd_object_mapping_list[i].element_bd;
+
+    mapping_initialized = TRUE;
+  }
+
+  if (element_rnd < 0 || element_rnd >= NUM_FILE_ELEMENTS)
+  {
+    Warn("invalid RND element %d", element_rnd);
+
+    return O_UNKNOWN;
+  }
+
+  return mapping_RND_to_BD[element_rnd];
+}
+
+int map_element_RND_to_BD_effect(int element_rnd, int action)
+{
+  static unsigned short mapping_RND_to_BD[NUM_FILE_ELEMENTS][NUM_ACTIONS];
+  static boolean mapping_initialized = FALSE;
+
+  if (!mapping_initialized)
+  {
+    int i, j;
+
+    // return "O_UNKNOWN" for all undefined elements in mapping array
+    for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+      for (j = 0; j < NUM_ACTIONS; j++)
+       mapping_RND_to_BD[i][j] = O_UNKNOWN;
+
+    for (i = 0; bd_object_mapping_list[i].element_bd != -1; i++)
     {
-      int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+      int element_rnd = bd_object_mapping_list[i].element_rnd;
+      int element_bd  = bd_object_mapping_list[i].element_bd;
+      int action      = bd_object_mapping_list[i].action;
 
-      getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
-                           pos->size, &deco_bitmap, &deco_x, &deco_y);
-      deco_xpos = (gfx->width  - pos->size) / 2;
-      deco_ypos = (gfx->height - pos->size) / 2;
+      if (action != -1)
+       mapping_RND_to_BD[element_rnd][action] = element_bd;
     }
 
-    gi = CreateGadget(GDI_CUSTOM_ID, id,
-                     GDI_IMAGE_ID, graphic,
-                     GDI_INFO_TEXT, toolbutton_info[i].infotext,
-                     GDI_X, base_x + x,
-                     GDI_Y, base_y + y,
-                     GDI_WIDTH, gfx->width,
-                     GDI_HEIGHT, gfx->height,
-                     GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
-                     GDI_STATE, GD_BUTTON_UNPRESSED,
-                     GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
-                     GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
-                     GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
-                     GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
-                     GDI_DECORATION_SIZE, pos->size, pos->size,
-                     GDI_DECORATION_SHIFTING, 1, 1,
-                     GDI_DIRECT_DRAW, FALSE,
-                     GDI_OVERLAY_TOUCH_BUTTON, is_touch_button,
-                     GDI_EVENT_MASK, event_mask,
-                     GDI_CALLBACK_ACTION, HandleToolButtons,
-                     GDI_END);
+    mapping_initialized = TRUE;
+  }
 
-    if (gi == NULL)
-      Fail("cannot create gadget");
+  if (element_rnd < 0 || element_rnd >= NUM_FILE_ELEMENTS)
+  {
+    Warn("invalid RND element %d", element_rnd);
 
-    tool_gadget[id] = gi;
+    return O_UNKNOWN;
   }
-}
 
-void FreeToolButtons(void)
-{
-  int i;
+  if (action < 0 || action >= NUM_ACTIONS)
+  {
+    Warn("invalid action %d", action);
 
-  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
-    FreeGadget(tool_gadget[i]);
+    return O_UNKNOWN;
+  }
+
+  return mapping_RND_to_BD[element_rnd][action];
 }
 
-static void UnmapToolButtons(void)
+int map_element_BD_to_RND_cave(int element_bd)
 {
-  int i;
+  static unsigned short mapping_BD_to_RND[O_MAX_ALL];
+  static boolean mapping_initialized = FALSE;
 
-  for (i = 0; i < NUM_TOOL_BUTTONS; i++)
-    UnmapGadget(tool_gadget[i]);
+  if (!mapping_initialized)
+  {
+    int i;
+
+    // return "EL_UNKNOWN" for all undefined elements in mapping array
+    for (i = 0; i < O_MAX_ALL; i++)
+      mapping_BD_to_RND[i] = EL_UNKNOWN;
+
+    for (i = 0; bd_object_mapping_list[i].element_bd != -1; i++)
+      if (bd_object_mapping_list[i].is_rnd_to_bd_mapping)
+       mapping_BD_to_RND[bd_object_mapping_list[i].element_bd] =
+         bd_object_mapping_list[i].element_rnd;
+
+    mapping_initialized = TRUE;
+  }
+
+  if (element_bd < 0 || element_bd >= O_MAX_ALL)
+  {
+    Warn("invalid BD element %d", element_bd);
+
+    return EL_UNKNOWN;
+  }
+
+  return mapping_BD_to_RND[element_bd];
 }
 
-static void HandleToolButtons(struct GadgetInfo *gi)
+int map_element_BD_to_RND_game(int element_bd)
 {
-  request_gadget_id = gi->custom_id;
+  static unsigned short mapping_BD_to_RND[O_MAX_ALL];
+  static boolean mapping_initialized = FALSE;
+
+  if (!mapping_initialized)
+  {
+    int i;
+
+    // return "EL_UNKNOWN" for all undefined elements in mapping array
+    for (i = 0; i < O_MAX_ALL; i++)
+      mapping_BD_to_RND[i] = EL_UNKNOWN;
+
+    for (i = 0; bd_object_mapping_list[i].element_bd != -1; i++)
+      mapping_BD_to_RND[bd_object_mapping_list[i].element_bd] =
+       bd_object_mapping_list[i].element_rnd;
+
+    mapping_initialized = TRUE;
+  }
+
+  if (element_bd < 0 || element_bd >= O_MAX_ALL)
+  {
+    Warn("invalid BD element %d", element_bd);
+
+    return EL_UNKNOWN;
+  }
+
+  return mapping_BD_to_RND[element_bd];
 }
 
 static struct Mapping_EM_to_RND_object
@@ -8138,6 +9968,10 @@ int map_element_RND_to_MM(int element_rnd)
          element_rnd <= EL_MM_END_2 ?
          EL_MM_START_2_NATIVE + element_rnd - EL_MM_START_2 :
 
+         element_rnd >= EL_MM_START_3 &&
+         element_rnd <= EL_MM_END_3 ?
+         EL_MM_START_3_NATIVE + element_rnd - EL_MM_START_3 :
+
          element_rnd >= EL_CHAR_START &&
          element_rnd <= EL_CHAR_END ?
          EL_MM_CHAR_START_NATIVE + element_rnd - EL_CHAR_START :
@@ -8146,10 +9980,6 @@ int map_element_RND_to_MM(int element_rnd)
          element_rnd <= EL_MM_RUNTIME_END ?
          EL_MM_RUNTIME_START_NATIVE + element_rnd - EL_MM_RUNTIME_START :
 
-         element_rnd >= EL_MM_DUMMY_START &&
-         element_rnd <= EL_MM_DUMMY_END ?
-         EL_MM_DUMMY_START_NATIVE + element_rnd - EL_MM_DUMMY_START :
-
          EL_MM_EMPTY_NATIVE);
 }
 
@@ -8167,6 +9997,10 @@ int map_element_MM_to_RND(int element_mm)
          element_mm <= EL_MM_END_2_NATIVE ?
          EL_MM_START_2 + element_mm - EL_MM_START_2_NATIVE :
 
+         element_mm >= EL_MM_START_3_NATIVE &&
+         element_mm <= EL_MM_END_3_NATIVE ?
+         EL_MM_START_3 + element_mm - EL_MM_START_3_NATIVE :
+
          element_mm >= EL_MM_CHAR_START_NATIVE &&
          element_mm <= EL_MM_CHAR_END_NATIVE ?
          EL_CHAR_START + element_mm - EL_MM_CHAR_START_NATIVE :
@@ -8175,10 +10009,6 @@ int map_element_MM_to_RND(int element_mm)
          element_mm <= EL_MM_RUNTIME_END_NATIVE ?
          EL_MM_RUNTIME_START + element_mm - EL_MM_RUNTIME_START_NATIVE :
 
-         element_mm >= EL_MM_DUMMY_START_NATIVE &&
-         element_mm <= EL_MM_DUMMY_END_NATIVE ?
-         EL_MM_DUMMY_START + element_mm - EL_MM_DUMMY_START_NATIVE :
-
          EL_EMPTY);
 }
 
@@ -8272,6 +10102,11 @@ int el2img_mm(int element_mm)
   return el2img(map_element_MM_to_RND(element_mm));
 }
 
+int el_act2img_mm(int element_mm, int action)
+{
+  return el_act2img(map_element_MM_to_RND(element_mm), action);
+}
+
 int el_act_dir2img(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
@@ -8330,6 +10165,29 @@ int el2edimg(int element)
   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
 }
 
+int el2edimg_with_frame(int element, int *graphic, int *frame)
+{
+  *graphic = el2edimg(element);
+  *frame = 0;
+
+  if (*graphic == IMG_UNKNOWN)
+  {
+    // no graphic defined -- if BD style, try to get runtime ("effect") element graphics
+    // (normal BD style elements have graphics, but runtime ("effects") elements do not)
+    int element_bd = map_element_RND_to_BD_cave(element);
+
+    if (element_bd != O_UNKNOWN)
+    {
+      struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[element_bd][0];
+
+      *graphic = g_bd->graphic;
+      *frame   = g_bd->frame;
+    }
+  }
+
+  return *graphic;
+}
+
 int el2preimg(int element)
 {
   element = GFX_ELEMENT(element);
@@ -8487,7 +10345,9 @@ boolean isActivePlayer_EM(int player_nr)
 
 unsigned int InitRND(int seed)
 {
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  if (level.game_engine_type == GAME_ENGINE_TYPE_BD)
+    return InitEngineRandom_BD(seed);
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
     return InitEngineRandom_EM(seed);
   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
     return InitEngineRandom_SP(seed);
@@ -8497,14 +10357,15 @@ unsigned int InitRND(int seed)
     return InitEngineRandom_RND(seed);
 }
 
-static struct Mapping_EM_to_RND_object object_mapping[GAME_TILE_MAX];
-static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][PLY_MAX];
+static struct Mapping_BD_to_RND_object bd_object_mapping[O_MAX_ALL];
+static struct Mapping_EM_to_RND_object em_object_mapping[GAME_TILE_MAX];
+static struct Mapping_EM_to_RND_player em_player_mapping[MAX_PLAYERS][PLY_MAX];
 
 static int get_effective_element_EM(int tile, int frame_em)
 {
-  int element             = object_mapping[tile].element_rnd;
-  int action              = object_mapping[tile].action;
-  boolean is_backside     = object_mapping[tile].is_backside;
+  int element             = em_object_mapping[tile].element_rnd;
+  int action              = em_object_mapping[tile].action;
+  boolean is_backside     = em_object_mapping[tile].is_backside;
   boolean action_removing = (action == ACTION_DIGGING ||
                             action == ACTION_SNAPPING ||
                             action == ACTION_COLLECTING);
@@ -8652,8 +10513,8 @@ void ResetGfxAnimation_EM(int x, int y, int tile)
 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
                        int tile, int frame_em, int x, int y)
 {
-  int action = object_mapping[tile].action;
-  int direction = object_mapping[tile].direction;
+  int action = em_object_mapping[tile].action;
+  int direction = em_object_mapping[tile].direction;
   int effective_element = get_effective_element_EM(tile, frame_em);
   int graphic = (direction == MV_NONE ?
                 el_act2img(effective_element, action) :
@@ -8692,11 +10553,11 @@ void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
   }
   else if (action_moving)
   {
-    boolean is_backside = object_mapping[tile].is_backside;
+    boolean is_backside = em_object_mapping[tile].is_backside;
 
     if (is_backside)
     {
-      int direction = object_mapping[tile].direction;
+      int direction = em_object_mapping[tile].direction;
       int move_dir = (action_falling ? MV_DOWN : direction);
 
       GfxFrame[x][y]++;
@@ -8729,6 +10590,8 @@ void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
 
   if (graphic_info[graphic].anim_global_sync)
     sync_frame = FrameCounter;
+  else if (graphic_info[graphic].anim_global_anim_sync)
+    sync_frame = getGlobalAnimSyncFrame();
   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
     sync_frame = GfxFrame[x][y];
   else
@@ -8749,9 +10612,9 @@ void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
                                  int tile, int frame_em, int x, int y)
 {
-  int action = object_mapping[tile].action;
-  int direction = object_mapping[tile].direction;
-  boolean is_backside = object_mapping[tile].is_backside;
+  int action = em_object_mapping[tile].action;
+  int direction = em_object_mapping[tile].direction;
+  boolean is_backside = em_object_mapping[tile].is_backside;
   int effective_element = get_effective_element_EM(tile, frame_em);
   int effective_action = action;
   int graphic = (direction == MV_NONE ?
@@ -8788,6 +10651,8 @@ void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
 
   if (graphic_info[graphic].anim_global_sync)
     sync_frame = FrameCounter;
+  else if (graphic_info[graphic].anim_global_anim_sync)
+    sync_frame = getGlobalAnimSyncFrame();
   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
     sync_frame = GfxFrame[x][y];
   else
@@ -8813,9 +10678,9 @@ void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
                                  int player_nr, int anim, int frame_em)
 {
-  int element   = player_mapping[player_nr][anim].element_rnd;
-  int action    = player_mapping[player_nr][anim].action;
-  int direction = player_mapping[player_nr][anim].direction;
+  int element   = em_player_mapping[player_nr][anim].element_rnd;
+  int action    = em_player_mapping[player_nr][anim].action;
+  int direction = em_player_mapping[player_nr][anim].direction;
   int graphic = (direction == MV_NONE ?
                 el_act2img(element, action) :
                 el_act_dir2img(element, action, direction));
@@ -8838,6 +10703,105 @@ void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
                      &g_em->src_x, &g_em->src_y, FALSE);
 }
 
+#define BD_GFX_RANGE(a, n, i)          ((i) >= (a) && (i) < (a) + (n))
+#define BD_GFX_FRAME(b, i)             (((i) - (b)) * 8)
+
+void InitGraphicInfo_BD(void)
+{
+  int i, j;
+
+  if (graphic_info == NULL)            // still at startup phase
+    return;
+
+  // always start with reliable default values
+  for (i = 0; i < O_MAX_ALL; i++)
+  {
+    bd_object_mapping[i].element_rnd = EL_UNKNOWN;
+    bd_object_mapping[i].action = ACTION_DEFAULT;
+    bd_object_mapping[i].direction = MV_NONE;
+  }
+
+  for (i = 0; bd_object_mapping_list[i].element_bd != -1; i++)
+  {
+    int e = bd_object_mapping_list[i].element_bd;
+
+    bd_object_mapping[e].element_rnd = bd_object_mapping_list[i].element_rnd;
+
+    if (bd_object_mapping_list[i].action != -1)
+      bd_object_mapping[e].action = bd_object_mapping_list[i].action;
+
+    if (bd_object_mapping_list[i].direction != -1)
+      bd_object_mapping[e].direction =
+       MV_DIR_FROM_BIT(bd_object_mapping_list[i].direction);
+  }
+
+  for (i = 0; i < O_MAX_ALL; i++)
+  {
+    int element = bd_object_mapping[i].element_rnd;
+    int action = bd_object_mapping[i].action;
+    int direction = bd_object_mapping[i].direction;
+
+    for (j = 0; j < 8; j++)
+    {
+      int effective_element = element;
+      int effective_action = action;
+      int graphic = (el_act_dir2img(effective_element, effective_action,
+                                   direction));
+      struct GraphicInfo *g = &graphic_info[graphic];
+      struct GraphicInfo_BD *g_bd = &graphic_info_bd_object[i][j];
+      Bitmap *src_bitmap;
+      int src_x, src_y;
+      int sync_frame = (BD_GFX_RANGE(O_PRE_PL_1, 3, i)        ? BD_GFX_FRAME(O_PRE_PL_1, i) :
+                       BD_GFX_RANGE(O_PRE_DIA_1, 5, i)       ? BD_GFX_FRAME(O_PRE_DIA_1, i) :
+                       BD_GFX_RANGE(O_PRE_STONE_1, 4, i)     ? BD_GFX_FRAME(O_PRE_STONE_1, i) :
+                       BD_GFX_RANGE(O_PRE_STEEL_1, 4, i)     ? BD_GFX_FRAME(O_PRE_STEEL_1, i) :
+                       BD_GFX_RANGE(O_BOMB_TICK_1, 7, i)     ? BD_GFX_FRAME(O_BOMB_TICK_1, i) :
+                       BD_GFX_RANGE(O_BOMB_EXPL_1, 4, i)     ? BD_GFX_FRAME(O_BOMB_EXPL_1, i) :
+                       BD_GFX_RANGE(O_NUT_EXPL_1, 4, i)      ? BD_GFX_FRAME(O_NUT_EXPL_1, i) :
+                       BD_GFX_RANGE(O_GHOST_EXPL_1, 4, i)    ? BD_GFX_FRAME(O_GHOST_EXPL_1, i) :
+                       BD_GFX_RANGE(O_EXPLODE_1, 5, i)       ? BD_GFX_FRAME(O_EXPLODE_1, i) :
+                       BD_GFX_RANGE(O_PRE_CLOCK_1, 4, i)     ? BD_GFX_FRAME(O_PRE_CLOCK_1, i) :
+                       BD_GFX_RANGE(O_NITRO_EXPL_1, 4, i)    ? BD_GFX_FRAME(O_NITRO_EXPL_1, i) :
+                       BD_GFX_RANGE(O_AMOEBA_2_EXPL_1, 4, i) ? BD_GFX_FRAME(O_AMOEBA_2_EXPL_1, i):
+                       i == O_INBOX_OPEN || i == O_OUTBOX_OPEN ? j :
+                       j * 2);
+      int frame = getAnimationFrame(g->anim_frames,
+                                   g->anim_delay,
+                                   g->anim_mode,
+                                   g->anim_start_frame,
+                                   sync_frame);
+
+      getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
+
+      g_bd->bitmap = src_bitmap;
+      g_bd->src_x  = src_x;
+      g_bd->src_y  = src_y;
+      g_bd->width  = TILEX;
+      g_bd->height = TILEY;
+
+      g_bd->graphic = graphic;
+      g_bd->frame = frame;
+    }
+  }
+
+  // game graphics template for level-specific colors for native BD levels
+  int graphic = IMG_BDX_GAME_GRAPHICS_COLOR_TEMPLATE;
+  struct GraphicInfo_BD *g_bd = &graphic_info_bd_color_template;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+
+  getGraphicSourceExt(graphic, 0, &src_bitmap, &src_x, &src_y, FALSE);
+
+  g_bd->bitmap = src_bitmap;
+  g_bd->src_x  = src_x;
+  g_bd->src_y  = src_y;
+  g_bd->width  = TILEX;
+  g_bd->height = TILEY;
+
+  g_bd->graphic = graphic;
+  g_bd->frame = 0;
+}
+
 void InitGraphicInfo_EM(void)
 {
   int i, j, p;
@@ -8845,10 +10809,10 @@ void InitGraphicInfo_EM(void)
   // always start with reliable default values
   for (i = 0; i < GAME_TILE_MAX; i++)
   {
-    object_mapping[i].element_rnd = EL_UNKNOWN;
-    object_mapping[i].is_backside = FALSE;
-    object_mapping[i].action = ACTION_DEFAULT;
-    object_mapping[i].direction = MV_NONE;
+    em_object_mapping[i].element_rnd = EL_UNKNOWN;
+    em_object_mapping[i].is_backside = FALSE;
+    em_object_mapping[i].action = ACTION_DEFAULT;
+    em_object_mapping[i].direction = MV_NONE;
   }
 
   // always start with reliable default values
@@ -8856,9 +10820,9 @@ void InitGraphicInfo_EM(void)
   {
     for (i = 0; i < PLY_MAX; i++)
     {
-      player_mapping[p][i].element_rnd = EL_UNKNOWN;
-      player_mapping[p][i].action = ACTION_DEFAULT;
-      player_mapping[p][i].direction = MV_NONE;
+      em_player_mapping[p][i].element_rnd = EL_UNKNOWN;
+      em_player_mapping[p][i].action = ACTION_DEFAULT;
+      em_player_mapping[p][i].direction = MV_NONE;
     }
   }
 
@@ -8866,14 +10830,14 @@ void InitGraphicInfo_EM(void)
   {
     int e = em_object_mapping_list[i].element_em;
 
-    object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
-    object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
+    em_object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
+    em_object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
 
     if (em_object_mapping_list[i].action != -1)
-      object_mapping[e].action = em_object_mapping_list[i].action;
+      em_object_mapping[e].action = em_object_mapping_list[i].action;
 
     if (em_object_mapping_list[i].direction != -1)
-      object_mapping[e].direction =
+      em_object_mapping[e].direction =
        MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
   }
 
@@ -8882,22 +10846,22 @@ void InitGraphicInfo_EM(void)
     int a = em_player_mapping_list[i].action_em;
     int p = em_player_mapping_list[i].player_nr;
 
-    player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
+    em_player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
 
     if (em_player_mapping_list[i].action != -1)
-      player_mapping[p][a].action = em_player_mapping_list[i].action;
+      em_player_mapping[p][a].action = em_player_mapping_list[i].action;
 
     if (em_player_mapping_list[i].direction != -1)
-      player_mapping[p][a].direction =
+      em_player_mapping[p][a].direction =
        MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
   }
 
   for (i = 0; i < GAME_TILE_MAX; i++)
   {
-    int element = object_mapping[i].element_rnd;
-    int action = object_mapping[i].action;
-    int direction = object_mapping[i].direction;
-    boolean is_backside = object_mapping[i].is_backside;
+    int element = em_object_mapping[i].element_rnd;
+    int action = em_object_mapping[i].action;
+    int direction = em_object_mapping[i].direction;
+    boolean is_backside = em_object_mapping[i].is_backside;
     boolean action_exploding = ((action == ACTION_EXPLODING ||
                                 action == ACTION_SMASHED_BY_ROCK ||
                                 action == ACTION_SMASHED_BY_SPRING) &&
@@ -9169,10 +11133,10 @@ void InitGraphicInfo_EM(void)
   {
     for (j = 0; j < 8; j++)
     {
-      int element = object_mapping[i].element_rnd;
-      int action = object_mapping[i].action;
-      int direction = object_mapping[i].direction;
-      boolean is_backside = object_mapping[i].is_backside;
+      int element = em_object_mapping[i].element_rnd;
+      int action = em_object_mapping[i].action;
+      int direction = em_object_mapping[i].direction;
+      boolean is_backside = em_object_mapping[i].is_backside;
       int graphic_action  = el_act_dir2img(element, action, direction);
       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
 
@@ -9212,9 +11176,9 @@ void InitGraphicInfo_EM(void)
   {
     for (i = 0; i < PLY_MAX; i++)
     {
-      int element = player_mapping[p][i].element_rnd;
-      int action = player_mapping[p][i].action;
-      int direction = player_mapping[p][i].direction;
+      int element = em_player_mapping[p][i].element_rnd;
+      int action = em_player_mapping[p][i].action;
+      int direction = em_player_mapping[p][i].direction;
 
       for (j = 0; j < 8; j++)
       {
@@ -9251,7 +11215,7 @@ void InitGraphicInfo_EM(void)
   }
 }
 
-static void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
+static void CheckSaveEngineSnapshot_EM(int frame,
                                       boolean any_player_moving,
                                       boolean any_player_snapping,
                                       boolean any_player_dropping)
@@ -9308,7 +11272,7 @@ static void CheckSaveEngineSnapshot_MM(boolean element_clicked,
   }
 }
 
-boolean CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
+boolean CheckSingleStepMode_EM(int frame,
                               boolean any_player_moving,
                               boolean any_player_snapping,
                               boolean any_player_dropping)
@@ -9317,7 +11281,7 @@ boolean CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
     if (frame == 7 && !any_player_dropping && FrameCounter > 6)
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
-  CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
+  CheckSaveEngineSnapshot_EM(frame, any_player_moving,
                             any_player_snapping, any_player_dropping);
 
   return tape.pausing;
@@ -9351,7 +11315,7 @@ void CheckSingleStepMode_MM(boolean element_clicked,
 }
 
 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
-                        int graphic, int sync_frame, int x, int y)
+                        int graphic, int sync_frame)
 {
   int frame = getGraphicAnimationFrame(graphic, sync_frame);
 
@@ -9368,6 +11332,17 @@ int getGraphicInfo_Delay(int graphic)
   return graphic_info[graphic].anim_delay;
 }
 
+boolean getGraphicInfo_NewFrame(int x, int y, int graphic)
+{
+  if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    return FALSE;
+
+  if (ANIM_MODE(graphic) & (ANIM_TILED | ANIM_RANDOM_STATIC))
+    return FALSE;
+
+  return TRUE;
+}
+
 void PlayMenuSoundExt(int sound)
 {
   if (sound == SND_UNDEFINED)
@@ -9484,6 +11459,27 @@ void PlaySoundSelecting(void)
 #endif
 }
 
+void ToggleAudioSampleRateIfNeeded(void)
+{
+  int setup_audio_sample_rate = (setup.audio_sample_rate_44100 ? 44100 : 22050);
+
+  // if setup and audio sample rate are already matching, nothing do do
+  if ((setup_audio_sample_rate == audio.sample_rate) ||
+      !audio.sound_available)
+    return;
+
+#if 1
+  // apparently changing the audio output sample rate does not work at runtime,
+  // so currently the program has to be restarted to apply the new sample rate
+  Request("Please restart the program to change audio sample rate!", REQ_CONFIRM);
+#else
+  SDLReopenAudio();
+
+  // set setup value according to successfully changed audio sample rate
+  setup.audio_sample_rate_44100 = (audio.sample_rate == 44100);
+#endif
+}
+
 void ToggleFullscreenIfNeeded(void)
 {
   // if setup and video fullscreen state are already matching, nothing do do
@@ -9690,9 +11686,9 @@ void ChangeViewportPropertiesIfNeeded(void)
 {
   boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
                               FALSE : setup.small_game_graphics);
-  int gfx_game_mode = game_status;
-  int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
-                       game_status);
+  int gfx_game_mode = getGlobalGameStatus(game_status);
+  int gfx_game_mode2 = (gfx_game_mode == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
+                       gfx_game_mode);
   struct RectWithBorder *vp_window    = &viewport.window[gfx_game_mode];
   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
   struct RectWithBorder *vp_door_1    = &viewport.door_1[gfx_game_mode];
@@ -9734,6 +11730,7 @@ void ChangeViewportPropertiesIfNeeded(void)
   boolean init_gfx_buffers = FALSE;
   boolean init_video_buffer = FALSE;
   boolean init_gadgets_and_anims = FALSE;
+  boolean init_bd_graphics = FALSE;
   boolean init_em_graphics = FALSE;
 
   if (new_win_xsize != WIN_XSIZE ||
@@ -9832,7 +11829,8 @@ void ChangeViewportPropertiesIfNeeded(void)
       // changing tile size invalidates scroll values of engine snapshots
       FreeEngineSnapshotSingle();
 
-      // changing tile size requires update of graphic mapping for EM engine
+      // changing tile size requires update of graphic mapping for BD/EM engine
+      init_bd_graphics = TRUE;
       init_em_graphics = TRUE;
     }
 
@@ -9899,8 +11897,222 @@ void ChangeViewportPropertiesIfNeeded(void)
     InitGlobalAnimations();
   }
 
+  if (init_bd_graphics)
+  {
+    InitGraphicInfo_BD();
+  }
+
   if (init_em_graphics)
   {
     InitGraphicInfo_EM();
   }
 }
+
+void OpenURL(char *url)
+{
+#if SDL_VERSION_ATLEAST(2,0,14)
+  SDL_OpenURL(url);
+#else
+  Warn("SDL_OpenURL(\"%s\") not supported by SDL %d.%d.%d!",
+       url, SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
+  Warn("Please upgrade to at least SDL 2.0.14 for URL support!");
+#endif
+}
+
+void OpenURLFromHash(SetupFileHash *hash, int hash_key)
+{
+  OpenURL(getHashEntry(hash, int2str(hash_key, 0)));
+}
+
+
+// ============================================================================
+// tests
+// ============================================================================
+
+#if defined(PLATFORM_WINDOWS)
+/* FILETIME of Jan 1 1970 00:00:00. */
+static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL);
+
+/*
+ * timezone information is stored outside the kernel so tzp isn't used anymore.
+ *
+ * Note: this function is not for Win32 high precision timing purpose. See
+ * elapsed_time().
+ */
+static int gettimeofday_windows(struct timeval * tp, struct timezone * tzp)
+{
+  FILETIME    file_time;
+  SYSTEMTIME  system_time;
+  ULARGE_INTEGER ularge;
+
+  GetSystemTime(&system_time);
+  SystemTimeToFileTime(&system_time, &file_time);
+  ularge.LowPart = file_time.dwLowDateTime;
+  ularge.HighPart = file_time.dwHighDateTime;
+
+  tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L);
+  tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+
+  return 0;
+}
+#endif
+
+static char *test_init_uuid_random_function_simple(void)
+{
+  static char seed_text[100];
+  unsigned int seed = InitSimpleRandom(NEW_RANDOMIZE);
+
+  sprintf(seed_text, "%d", seed);
+
+  return seed_text;
+}
+
+static char *test_init_uuid_random_function_better(void)
+{
+  static char seed_text[100];
+  struct timeval current_time;
+
+  gettimeofday(&current_time, NULL);
+
+  prng_seed_bytes(&current_time, sizeof(current_time));
+
+  sprintf(seed_text, "%ld.%ld",
+         (long)current_time.tv_sec,
+         (long)current_time.tv_usec);
+
+  return seed_text;
+}
+
+#if defined(PLATFORM_WINDOWS)
+static char *test_init_uuid_random_function_better_windows(void)
+{
+  static char seed_text[100];
+  struct timeval current_time;
+
+  gettimeofday_windows(&current_time, NULL);
+
+  prng_seed_bytes(&current_time, sizeof(current_time));
+
+  sprintf(seed_text, "%ld.%ld",
+         (long)current_time.tv_sec,
+         (long)current_time.tv_usec);
+
+  return seed_text;
+}
+#endif
+
+static unsigned int test_uuid_random_function_simple(int max)
+{
+  return GetSimpleRandom(max);
+}
+
+static unsigned int test_uuid_random_function_better(int max)
+{
+  return (max > 0 ? prng_get_uint() % max : 0);
+}
+
+#if defined(PLATFORM_WINDOWS)
+#define NUM_UUID_TESTS                 3
+#else
+#define NUM_UUID_TESTS                 2
+#endif
+
+static void TestGeneratingUUIDs_RunTest(int nr, int always_seed, int num_uuids)
+{
+  HashTable *hash_seeds =
+    create_hashtable(get_hash_from_string, hash_key_strings_are_equal, free, NULL);
+  HashTable *hash_uuids =
+    create_hashtable(get_hash_from_string, hash_key_strings_are_equal, free, NULL);
+  static char message[100];
+  int i;
+
+  char *random_name = (nr == 0 ? "simple" : "better");
+  char *random_type = (always_seed ? "always" : "only once");
+  char *(*init_random_function)(void) =
+    (nr == 0 ?
+     test_init_uuid_random_function_simple :
+     test_init_uuid_random_function_better);
+  unsigned int (*random_function)(int) =
+    (nr == 0 ?
+     test_uuid_random_function_simple :
+     test_uuid_random_function_better);
+  int xpos = 40;
+
+#if defined(PLATFORM_WINDOWS)
+  if (nr == 2)
+  {
+    random_name = "windows";
+    init_random_function = test_init_uuid_random_function_better_windows;
+  }
+#endif
+
+  ClearField();
+
+  DrawTextF(xpos, 40, FC_GREEN, "Test: Generating UUIDs");
+  DrawTextF(xpos, 80, FC_YELLOW, "Test %d.%d:", nr + 1, always_seed + 1);
+
+  DrawTextF(xpos, 100, FC_YELLOW, "Random Generator Name: %s", random_name);
+  DrawTextF(xpos, 120, FC_YELLOW, "Seeding Random Generator: %s", random_type);
+  DrawTextF(xpos, 140, FC_YELLOW, "Number of UUIDs generated: %d", num_uuids);
+
+  DrawTextF(xpos, 180, FC_GREEN, "Please wait ...");
+
+  BackToFront();
+
+  // always initialize random number generator at least once
+  init_random_function();
+
+  unsigned int time_start = SDL_GetTicks();
+
+  for (i = 0; i < num_uuids; i++)
+  {
+    if (always_seed)
+    {
+      char *seed = getStringCopy(init_random_function());
+
+      hashtable_remove(hash_seeds, seed);
+      hashtable_insert(hash_seeds, seed, "1");
+    }
+
+    char *uuid = getStringCopy(getUUIDExt(random_function));
+
+    hashtable_remove(hash_uuids, uuid);
+    hashtable_insert(hash_uuids, uuid, "1");
+  }
+
+  int num_unique_seeds = hashtable_count(hash_seeds);
+  int num_unique_uuids = hashtable_count(hash_uuids);
+
+  unsigned int time_needed = SDL_GetTicks() - time_start;
+
+  DrawTextF(xpos, 220, FC_YELLOW, "Time needed: %d ms", time_needed);
+
+  DrawTextF(xpos, 240, FC_YELLOW, "Number of unique UUIDs: %d", num_unique_uuids);
+
+  if (always_seed)
+    DrawTextF(xpos, 260, FC_YELLOW, "Number of unique seeds: %d", num_unique_seeds);
+
+  if (nr == NUM_UUID_TESTS - 1 && always_seed)
+    DrawTextF(xpos, 300, FC_GREEN, "All tests done!");
+  else
+    DrawTextF(xpos, 300, FC_GREEN, "Confirm dialog for next test ...");
+
+  sprintf(message, "Test %d.%d finished!", nr + 1, always_seed + 1);
+
+  Request(message, REQ_CONFIRM);
+
+  hashtable_destroy(hash_seeds);
+  hashtable_destroy(hash_uuids);
+}
+
+void TestGeneratingUUIDs(void)
+{
+  int num_uuids = 1000000;
+  int i, j;
+
+  for (i = 0; i < NUM_UUID_TESTS; i++)
+    for (j = 0; j < 2; j++)
+      TestGeneratingUUIDs_RunTest(i, j, num_uuids);
+
+  CloseAllAndExit(0);
+}
index 5a02dd113a63b79bfc54b61fbff643a66d75c369..8774909b256e98b29389f701ac006647915987dd 100644 (file)
 
 
 // for DrawElementShifted
-#define NO_CUTTING             0
-#define CUT_ABOVE              (1 << 0)
-#define CUT_BELOW              (1 << 1)
-#define CUT_LEFT               (1 << 2)
-#define CUT_RIGHT              (1 << 3)
+#define NO_CUTTING                     0
+#define CUT_ABOVE                      (1 << 0)
+#define CUT_BELOW                      (1 << 1)
+#define CUT_LEFT                       (1 << 2)
+#define CUT_RIGHT                      (1 << 3)
 
 // for masking functions
-#define NO_MASKING             0
-#define USE_MASKING            1
+#define NO_MASKING                     0
+#define USE_MASKING                    1
  
 // for MoveDoor
-#define DOOR_OPEN_1            (1 << 0)
-#define DOOR_OPEN_2            (1 << 1)
-#define DOOR_CLOSE_1           (1 << 2)
-#define DOOR_CLOSE_2           (1 << 3)
-#define DOOR_OPEN_ALL          (DOOR_OPEN_1 | DOOR_OPEN_2)
-#define DOOR_CLOSE_ALL         (DOOR_CLOSE_1 | DOOR_CLOSE_2)
-#define DOOR_ACTION_1          (DOOR_OPEN_1 | DOOR_CLOSE_1)
-#define DOOR_ACTION_2          (DOOR_OPEN_2 | DOOR_CLOSE_2)
-#define DOOR_ACTION            (DOOR_ACTION_1 | DOOR_ACTION_2)
-#define DOOR_COPY_BACK         (1 << 4)
-#define DOOR_NO_COPY_BACK      (1 << 5)
-#define DOOR_NO_DELAY          (1 << 6)
-#define DOOR_FORCE_ANIM                (1 << 7)
-#define DOOR_FORCE_REDRAW      (1 << 8)
-#define DOOR_GET_STATE         (1 << 9)
-#define DOOR_SET_STATE         (1 << 10)
-
-#define DOOR_1                 (DOOR_ACTION_1)
-#define DOOR_2                 (DOOR_ACTION_2)
-#define DOOR_OPEN              (DOOR_OPEN_ALL)
-#define DOOR_CLOSE             (DOOR_CLOSE_ALL)
+#define DOOR_OPEN_1                    (1 << 0)
+#define DOOR_OPEN_2                    (1 << 1)
+#define DOOR_CLOSE_1                   (1 << 2)
+#define DOOR_CLOSE_2                   (1 << 3)
+#define DOOR_OPEN_ALL                  (DOOR_OPEN_1 | DOOR_OPEN_2)
+#define DOOR_CLOSE_ALL                 (DOOR_CLOSE_1 | DOOR_CLOSE_2)
+#define DOOR_ACTION_1                  (DOOR_OPEN_1 | DOOR_CLOSE_1)
+#define DOOR_ACTION_2                  (DOOR_OPEN_2 | DOOR_CLOSE_2)
+#define DOOR_ACTION                    (DOOR_ACTION_1 | DOOR_ACTION_2)
+#define DOOR_COPY_BACK                 (1 << 4)
+#define DOOR_NO_COPY_BACK              (1 << 5)
+#define DOOR_NO_DELAY                  (1 << 6)
+#define DOOR_FORCE_ANIM                        (1 << 7)
+#define DOOR_FORCE_REDRAW              (1 << 8)
+#define DOOR_GET_STATE                 (1 << 9)
+#define DOOR_SET_STATE                 (1 << 10)
+
+#define DOOR_1                         (DOOR_ACTION_1)
+#define DOOR_2                         (DOOR_ACTION_2)
+#define DOOR_OPEN                      (DOOR_OPEN_ALL)
+#define DOOR_CLOSE                     (DOOR_CLOSE_ALL)
 
 #define DOOR_INDEX_FROM_TOKEN(x)       ((x) == DOOR_1 ? 0 : 1)
 #define DOOR_TOKEN_FROM_INDEX(x)       ((x) == 0 ? DOOR_1 ? : DOOR_2)
-#define REDRAW_DOOR_FROM_TOKEN(x)      ((x) == DOOR_1 ? REDRAW_DOOR_1 : \
-                                        REDRAW_DOOR_2)
+#define REDRAW_DOOR_FROM_TOKEN(x)      ((x) == DOOR_1 ? REDRAW_DOOR_1 : REDRAW_DOOR_2)
 
 // for Request
-#define REQ_ASK                        (1 << 0)
-#define REQ_CONFIRM            (1 << 1)
-#define REQ_PLAYER             (1 << 2)
-#define REQ_STAY_OPEN          (1 << 3)
-#define REQ_STAY_CLOSED                (1 << 4)
-#define REQ_REOPEN             (1 << 5)
-
-#define REQUEST_WAIT_FOR_INPUT (REQ_ASK | REQ_CONFIRM | REQ_PLAYER)
+#define REQ_ASK                                (1 << 0)
+#define REQ_CONFIRM                    (1 << 1)
+#define REQ_PLAYER                     (1 << 2)
+#define REQ_STAY_OPEN                  (1 << 3)
+#define REQ_STAY_CLOSED                        (1 << 4)
+#define REQ_REOPEN                     (1 << 5)
 
 
 int getFieldbufferOffsetX_RND(int, int);
@@ -85,7 +82,7 @@ void DrawMaskedBorder_DOOR_3(void);
 void DrawMaskedBorder_ALL(void);
 void DrawMaskedBorder(int);
 void DrawMaskedBorderToTarget(int);
-void DrawTileCursor(int);
+void DrawTileCursor(int, int);
 
 void SetDrawtoField(int);
 int GetDrawtoField(void);
@@ -108,9 +105,12 @@ void FadeSetDisabled(void);
 void FadeSkipNextFadeIn(void);
 void FadeSkipNextFadeOut(void);
 
+int getImageFromGraphicOrDefault(int, int);
 Bitmap *getGlobalBorderBitmapFromStatus(int);
 
 void ClearField(void);
+
+void SetBackgroundImage(int, int);
 void SetWindowBackgroundImageIfDefined(int);
 void SetMainBackgroundImageIfDefined(int);
 void SetDoorBackgroundImageIfDefined(int);
@@ -126,14 +126,17 @@ void RedrawGlobalBorder(void);
 
 void MarkTileDirty(int, int);
 void SetBorderElement(void);
-void FloodFillLevel(int, int, int, short[][MAX_LEV_FIELDY], int, int);
-void FloodFillLevelExt(int, int, int, int, int y, short field[][y], int, int);
+void FloodFillLevel(int, int, int, short[MAX_LEV_FIELDX][MAX_LEV_FIELDY], int, int);
+void FloodFillLevelExt(int, int, int, int x, int y, short field[x][y], int, int);
 
 void SetRandomAnimationValue(int, int);
+void SetAnimationFirstLevel(int);
 int getGraphicAnimationFrame(int, int);
+int getGraphicAnimationFrameXY(int, int, int);
 
 void DrawFixedGraphicAnimation(int, int, int);
 void DrawFixedGraphicAnimationExt(DrawBuffer *, int, int, int, int, int);
+void DrawSizedGraphicAnimationExt(DrawBuffer *, int, int, int, int, int, int);
 
 void DrawLevelGraphicAnimation(int, int, int);
 void DrawLevelElementAnimation(int, int, int);
@@ -182,6 +185,7 @@ void DrawLevelFieldCrumbled(int, int);
 void DrawLevelFieldCrumbledDigging(int, int, int, int);
 void DrawLevelFieldCrumbledNeighbours(int, int);
 void DrawScreenGraphic(int, int, int, int);
+void DrawLevelGraphic(int, int, int, int);
 void DrawScreenElement(int, int, int);
 void DrawLevelElement(int, int, int);
 void DrawScreenField(int, int);
@@ -197,7 +201,7 @@ void DrawMiniElementOrWall(int, int, int, int);
 
 void ShowEnvelope(int);
 void ShowEnvelopeDoor(char *, int);
-void DrawEnvelopeRequestToScreen(int, int);
+void DrawEnvelopeRequestToScreen(int);
 
 void DrawLevel(int);
 void DrawSizedLevel(int, int, int, int, int);
@@ -210,7 +214,7 @@ void DrawNetworkPlayers(void);
 void ClearNetworkPlayers(void);
 
 void WaitForEventToContinue(void);
-boolean Request(char *, unsigned int);
+int Request(char *, unsigned int);
 void InitGraphicCompatibilityInfo_Doors(void);
 void InitDoors(void);
 unsigned int OpenDoor(unsigned int);
@@ -225,6 +229,14 @@ void UndrawSpecialEditorDoor(void);
 void CreateToolButtons(void);
 void FreeToolButtons(void);
 
+int getEngineElement(int);
+int getDrawingElement(int);
+
+int map_element_RND_to_BD_cave(int);
+int map_element_RND_to_BD_effect(int, int);
+int map_element_BD_to_RND_cave(int);
+int map_element_BD_to_RND_game(int);
+
 int map_element_RND_to_EM_cave(int);
 int map_element_EM_to_RND_cave(int);
 int map_element_EM_to_RND_game(int);
@@ -252,6 +264,7 @@ int el_dir2img(int, int);
 int el2baseimg(int);
 int el2img(int);
 int el2edimg(int);
+int el2edimg_with_frame(int, int *, int *);
 int el2preimg(int);
 int el2panelimg(int);
 int font2baseimg(int);
@@ -269,6 +282,8 @@ int getBeltSwitchElementFromBeltNrAndBeltDirNr(int, int);
 int getBeltSwitchElementFromBeltNrAndBeltDir(int, int);
 
 unsigned int InitRND(int);
+
+void InitGraphicInfo_BD(void);
 void InitGraphicInfo_EM(void);
 
 void PlayMenuSoundExt(int);
@@ -290,6 +305,7 @@ void ResetFontStatus(void);
 
 void SetLevelSetInfo(char *, int);
 
+void ToggleAudioSampleRateIfNeeded(void);
 void ToggleFullscreenIfNeeded(void);
 void ChangeWindowScalingIfNeeded(void);
 void ChangeVsyncModeIfNeeded(void);
@@ -298,4 +314,9 @@ void ChangeViewportPropertiesIfNeeded(void);
 boolean CheckIfAllViewportsHaveChanged(void);
 boolean CheckFadeAll(void);
 
+void OpenURL(char *);
+void OpenURLFromHash(SetupFileHash *, int);
+
+void TestGeneratingUUIDs(void);
+
 #endif // TOOLS_H